﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область СлужебныйПрограммныйИнтерфейс

// Возвращает путь к рабочему каталогу пользователя.
Функция РабочийКаталогПользователя() Экспорт
	
	Возврат РаботаСФайламиСлужебныйКлиентПовтИсп.РабочийКаталогПользователя();
	
КонецФункции

// Открывает форму папки со списком файлов.
//
// Параметры:
//   СтандартнаяОбработка - Булево - передается "как есть" из параметров обработчика "Открытие".
//   Папка - СправочникСсылка.Файлы - открываемая папка.
//
Процедура РассылкаОтчетовПросмотрПапки(СтандартнаяОбработка, Папка) Экспорт
	
	СтандартнаяОбработка = Ложь;
	ПараметрыФормы = Новый Структура("Папка", Папка);
	ОткрытьФорму("Справочник.Файлы.Форма.Файлы", ПараметрыФормы, , Папка);
	
КонецПроцедуры

Процедура ПеренестиФайлы() Экспорт
	
	ОткрытьФорму("Обработка.ПереносФайлов.Форма");
	
КонецПроцедуры

// На основе переданного пути к файлу создает файл в программе и открывает карточку.
//
// Параметры:
//  ПараметрыВыполнения - Структура:
//       * ОбработчикРезультата - ОписаниеОповещения
//                              - Неопределено -  описание процедуры, принимающей результат работы метода.
//       * ПолноеИмяФайла - Строка - необязательный. Полный путь и имя файла на клиенте.
//             Если не указан, то будет открыт диалог для выбора файла.
//       * ВладелецФайла - ЛюбаяСсылка - владелец файла.
//       * ФормаВладелец - ФормаКлиентскогоПриложения - форма из которой вызвано создание файла.
//       * НеОткрыватьКарточкуПослеСозданияИзФайла - Булево.
//             - Истина когда карточка файла не открывается после создания.
//       * ИмяСоздаваемогоФайла - Строка - необязательный. Новое имя файла.
//
Процедура ДобавитьИзФайловойСистемыСРасширением(ПараметрыВыполнения) Экспорт
	
	Результат = ДобавитьИзФайловойСистемыСРасширениемСинхронно(ПараметрыВыполнения);
	Если Не Результат.ФайлДобавлен Тогда
		Если ЗначениеЗаполнено(Результат.ТекстОшибки) Тогда
			ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, Результат.ТекстОшибки, Неопределено);
		Иначе
			ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
		КонецЕсли;
		Возврат;
	КонецЕсли;
	
	Если ПараметрыВыполнения.НеОткрыватьКарточкуПослеСозданияИзФайла <> Истина Тогда
		ПараметрыФормы = Новый Структура("КарточкаОткрытаПослеСозданияФайла", Истина);
		ОписаниеОповещенияОЗакрытии = ОбработчикЗавершения(ПараметрыВыполнения.ОбработчикРезультата);
		РаботаСФайламиКлиент.ОткрытьФормуФайла(Результат.ФайлСсылка,, ПараметрыФормы, ОписаниеОповещенияОЗакрытии); 
	Иначе
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Результат);
	КонецЕсли;
	
КонецПроцедуры

// На основе переданного пути к файлу создает файл в программе и открывает карточку.
//
// Параметры: 
//  ПараметрыВыполнения - Структура:
//       * ПолноеИмяФайла - Строка - необязательный. Полный путь и имя файла на клиенте.
//                                   Если не указан, то будет открыт синхронный диалог для выбора файла.
//       * ВладелецФайла - ЛюбаяСсылка - владелец файла.
//       * УникальныйИдентификатор - УникальныйИдентификатор - идентификатор формы для хранения файла.
//       * ИмяСоздаваемогоФайла - Строка - необязательный. Новое имя файла.
//
// Возвращаемое значение:
//   Структура:
//       * ФайлДобавлен - Булево - успешно ли выполнена операция.
//       * ФайлСсылка - СправочникСсылка.Файлы
//       * ТекстОшибки - Строка.
//
Функция ДобавитьИзФайловойСистемыСРасширениемСинхронно(ПараметрыВыполнения) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("ФайлДобавлен", Ложь);
	Результат.Вставить("ФайлСсылка",   Неопределено);
	Результат.Вставить("ТекстОшибки",  "");
	
	ФильтрДиалога = ?(ПараметрыВыполнения.Свойство("ФильтрДиалогаВыбора"),
		ПараметрыВыполнения.ФильтрДиалогаВыбора, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Все файлы (%1)|%1'"), ПолучитьМаскуВсеФайлы()));
		
	Если Не ПараметрыВыполнения.Свойство("ПолноеИмяФайла") Тогда
		// Загрузить из файловой системы с расширением работы с файлами.
		ДиалогВыбораФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
		ДиалогВыбораФайла.МножественныйВыбор = Ложь;
		ДиалогВыбораФайла.Заголовок = НСтр("ru = 'Выбор файла'");
		ДиалогВыбораФайла.Фильтр = ФильтрДиалога;
		ДиалогВыбораФайла.Каталог = РаботаСФайламиСлужебныйВызовСервера.РабочийКаталогПапки(ПараметрыВыполнения.ВладелецФайла);
		Если НЕ ДиалогВыбораФайла.Выбрать() Тогда
			Возврат Результат;
		КонецЕсли;
		ПараметрыВыполнения.Вставить("ПолноеИмяФайла", ДиалогВыбораФайла.ПолноеИмяФайла);
	КонецЕсли;
	
	Если Не ПараметрыВыполнения.Свойство("ИмяСоздаваемогоФайла") Тогда
		ПараметрыВыполнения.Вставить("ИмяСоздаваемогоФайла", Неопределено);
	КонецЕсли;
	
	ДобавляемыйФайл = Новый Файл(ПараметрыВыполнения.ПолноеИмяФайла);
	Если Не ДобавляемыйФайл.Существует() Тогда
		ТекстОшибки = НСтр("ru = 'Указанный файл не существует:
			|%1'");
		Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, 
			ПараметрыВыполнения.ПолноеИмяФайла);
		Возврат Результат;
	КонецЕсли;

	Если ПараметрыВыполнения.Свойство("МаксимальныйРазмер")
		И ПараметрыВыполнения.МаксимальныйРазмер > 0
		И ДобавляемыйФайл.Размер() > ПараметрыВыполнения.МаксимальныйРазмер*1024*1024 Тогда
		
		ТекстОшибки = НСтр("ru = 'Размер файла превышает %1 Мб.'");
		Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, 
			ПараметрыВыполнения.МаксимальныйРазмер);
		
		Возврат Результат;
		
	КонецЕсли;
	
	ПроверитьВозможностьЗагрузкиФайла(ДобавляемыйФайл);
	
	ОбщиеНастройки = ОбщиеНастройкиРаботыСФайлами();
	ИзвлекатьТекстыФайловНаКлиенте = НЕ ОбщиеНастройки.ИзвлекатьТекстыФайловНаСервере;
	Если ИзвлекатьТекстыФайловНаКлиенте Тогда
		АдресВременногоХранилищаТекста = ИзвлечьТекстВоВременноеХранилище(ДобавляемыйФайл.ПолноеИмя,
			ПараметрыВыполнения.ФормаВладелец.УникальныйИдентификатор);
	Иначе
		АдресВременногоХранилищаТекста = "";
	КонецЕсли;
		
	// Помещение файла во временное хранилище.
	АдресВременногоХранилищаФайла = "";
	
	ПомещаемыеФайлы = Новый Массив;
	Описание = Новый ОписаниеПередаваемогоФайла(ДобавляемыйФайл.ПолноеИмя, "");
	ПомещаемыеФайлы.Добавить(Описание);
	
	ПомещенныеФайлы = Новый Массив;
	ФайлыПомещены = ПоместитьФайлы(ПомещаемыеФайлы, ПомещенныеФайлы, , Ложь, ПараметрыВыполнения.ФормаВладелец.УникальныйИдентификатор);
	Если НЕ ФайлыПомещены Тогда
		Возврат Результат;
	КонецЕсли;
	
	Если ПомещенныеФайлы.Количество() = 1 Тогда
		АдресВременногоХранилищаФайла = ПомещенныеФайлы[0].Хранение;
	КонецЕсли;
	
#Если МобильныйКлиент Тогда
	ПредставлениеНаМобильномУстройстве = ДобавляемыйФайл.ПолучитьПредставлениеФайлаБиблиотекиМобильногоУстройства();
	РасширениеФайла = ОбщегоНазначенияКлиентСервер.ПолучитьРасширениеИмениФайла(ПредставлениеНаМобильномУстройстве);
	ИмяФайлаБезРасширения = СтрЗаменить(ПредставлениеНаМобильномУстройстве, "." + РасширениеФайла, "");
#Иначе
	РасширениеФайла = ОбщегоНазначенияКлиентСервер.РасширениеБезТочки(ДобавляемыйФайл.Расширение);
	ИмяФайлаБезРасширения = ДобавляемыйФайл.ИмяБезРасширения;
#КонецЕсли
	
	Если ПараметрыВыполнения.ИмяСоздаваемогоФайла <> Неопределено Тогда
		ИмяСоздания = ПараметрыВыполнения.ИмяСоздаваемогоФайла;
	Иначе
		ИмяСоздания = ИмяФайлаБезРасширения;
	КонецЕсли;
	
	// Создание карточки Файла в БД.
	Попытка
		
		Если РаботаСФайламиСлужебныйКлиентПовтИсп.ЭтоСправочникФайлы(ПараметрыВыполнения.ВладелецФайла) Тогда
			
			СведенияОФайле = РаботаСФайламиКлиентСервер.СведенияОФайле("ФайлСВерсией", ДобавляемыйФайл);
			СведенияОФайле.АдресВременногоХранилищаФайла = АдресВременногоХранилищаФайла;
			СведенияОФайле.АдресВременногоХранилищаТекста = АдресВременногоХранилищаТекста;
			СведенияОФайле.ЗаписатьВИсторию = Истина;
			СведенияОФайле.ИмяБезРасширения = ИмяСоздания;
			СведенияОФайле.РасширениеБезТочки = РасширениеФайла;
			Результат.ФайлСсылка = РаботаСФайламиСлужебныйВызовСервера.СоздатьФайлСВерсией(ПараметрыВыполнения.ВладелецФайла, СведенияОФайле);
			
		Иначе
			
			ПараметрыФайла = РаботаСФайламиСлужебныйКлиентСервер.ПараметрыДобавленияФайла();
			ПараметрыФайла.ВладелецФайлов = ПараметрыВыполнения.ВладелецФайла;
			ПараметрыФайла.ИмяБезРасширения = ИмяФайлаБезРасширения;
			ПараметрыФайла.РасширениеБезТочки = РасширениеФайла;
			
			Результат.ФайлСсылка = РаботаСФайламиСлужебныйВызовСервера.ДобавитьФайл(ПараметрыФайла,
				АдресВременногоХранилищаФайла,
				АдресВременногоХранилищаТекста);
				
		КонецЕсли;
		
		Результат.ФайлДобавлен = Истина;
		
	Исключение
		Результат.ТекстОшибки = ОшибкаСозданияНовогоФайла(ИнформацияОбОшибке());
	КонецПопытки;
	
	Если Результат.ТекстОшибки <> "" Тогда
		Возврат Результат;
	КонецЕсли;
	
	ПараметрыОповещения = ПараметрыОповещенияЗаписиФайла();
	ПараметрыОповещения.Владелец = ПараметрыВыполнения.ВладелецФайла;
	ПараметрыОповещения.Файл = Результат.ФайлСсылка;
	ПараметрыОповещения.ЭтоНовый = Истина;
	Оповестить("Запись_Файл", ПараметрыОповещения, Результат.ФайлСсылка);
	
	ПоказатьОповещениеПользователя(
		НСтр("ru = 'Создание:'"),
		ПолучитьНавигационнуюСсылку(Результат.ФайлСсылка),
		Результат.ФайлСсылка,
		БиблиотекаКартинок.Информация32);
	
	Возврат Результат;
	
КонецФункции

// Продолжение процедуры ПрисоединенныеФайлыКлиент.ДобавитьФайлы.
Процедура ДобавитьФайлыРасширениеПредложено(РасширениеРаботыСФайламиПодключено, ДополнительныеПараметры) Экспорт
	
	ВладелецФайла = ДополнительныеПараметры.ВладелецФайла;
	ИдентификаторФормы = ДополнительныеПараметры.ИдентификаторФормы;
	
	Если Не ДополнительныеПараметры.Свойство("Фильтр") Тогда
		ДополнительныеПараметры.Вставить("Фильтр","");
	КонецЕсли;
	
	Если РасширениеРаботыСФайламиПодключено Тогда
		
		Фильтр = ДополнительныеПараметры.Фильтр;
		ОткрыватьКарточкуПослеСозданияИзФайла = Ложь;
		Если ДополнительныеПараметры.Свойство("НеОткрыватьКарточкуПослеСозданияИзФайла") Тогда
			ОткрыватьКарточкуПослеСозданияИзФайла = Не ДополнительныеПараметры.НеОткрыватьКарточкуПослеСозданияИзФайла;
		КонецЕсли;
		
		ВыбранныеФайлы = Новый Массив;
		
		Если Не ДополнительныеПараметры.Свойство("ПолноеИмяФайла") Тогда
			ВыборФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
			ВыборФайла.МножественныйВыбор = Истина;
			ВыборФайла.Заголовок = НСтр("ru = 'Выбор файла'");
			ВыборФайла.Фильтр = ?(ЗначениеЗаполнено(Фильтр), Фильтр, НСтр("ru = 'Все файлы'") + " (*.*)|*.*");
			Если ВыборФайла.Выбрать() Тогда
				ВыбранныеФайлы = ВыборФайла.ВыбранныеФайлы;
			КонецЕсли;
		Иначе
			ВыбранныеФайлы.Добавить(ДополнительныеПараметры.ПолноеИмяФайла);
		КонецЕсли;
		
		ИмяСоздаваемогоФайла = "";
		Если ДополнительныеПараметры.Свойство("ИмяСоздаваемогоФайла") Тогда
			ИмяСоздаваемогоФайла = ДополнительныеПараметры.ИмяСоздаваемогоФайла;
		КонецЕсли;
		
		Если ВыбранныеФайлы.Количество() > 0  Тогда
			ПрисоединенныеФайлыМассив = Новый Массив;
			ПоместитьВыбранныеФайлыВХранилище(
				ВыбранныеФайлы,
				ВладелецФайла,
				ПрисоединенныеФайлыМассив,
				ИдентификаторФормы,
				ИмяСоздаваемогоФайла,
				ДополнительныеПараметры.ГруппаФайлов);
			
			Если ПрисоединенныеФайлыМассив.Количество() = 1 И ОткрыватьКарточкуПослеСозданияИзФайла Тогда
				ПрисоединенныйФайл = ПрисоединенныеФайлыМассив[0];
				
				ПоказатьОповещениеПользователя(
					НСтр("ru = 'Создание:'"),
					ПолучитьНавигационнуюСсылку(ПрисоединенныйФайл),
					ПрисоединенныйФайл,
					БиблиотекаКартинок.Информация32);
				
				ПараметрыФормы = Новый Структура("ЭтоНовый", Истина);
				РаботаСФайламиКлиент.ОткрытьФормуФайла(ПрисоединенныйФайл,, ПараметрыФормы)
			КонецЕсли;
			
			Если ПрисоединенныеФайлыМассив.Количество() > 0 Тогда
				ОповеститьОбИзменении(ПрисоединенныеФайлыМассив[0]);
				ОповеститьОбИзменении(ВладелецФайла);
				ПараметрыОповещения = ПараметрыОповещенияЗаписиФайла();
				ПараметрыОповещения.Владелец = ВладелецФайла;
				ПараметрыОповещения.Файл = ПрисоединенныеФайлыМассив[0];
				ПараметрыОповещения.ЭтоНовый = Истина;
				Оповестить("Запись_Файл", ПараметрыОповещения, ПрисоединенныеФайлыМассив);
			КонецЕсли;
			
			Если ДополнительныеПараметры.Свойство("ОбработчикРезультата")
				И ДополнительныеПараметры.ОбработчикРезультата <> Неопределено Тогда
				ВыполнитьОбработкуОповещения(ДополнительныеПараметры.ОбработчикРезультата, ПрисоединенныеФайлыМассив);
			КонецЕсли;
			
		КонецЕсли;
		
	Иначе // Если веб-клиент без подключенного расширения.
		ОписаниеОповещения = Новый ОписаниеОповещения("ДобавитьФайлыЗавершение", ЭтотОбъект, ДополнительныеПараметры);
		ПоместитьВыбранныеФайлыВХранилищеВеб(ОписаниеОповещения, ВладелецФайла, ИдентификаторФормы);
	КонецЕсли;
	
КонецПроцедуры

// Показывает стандартное предупреждение.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  ПредставлениеКоманды - Строка - имя команды, для выполнения которой необходимо расширение.
//
Процедура ПоказатьПредупреждениеОНеобходимостиРасширенияРаботыСФайлами(ОбработчикРезультата, ПредставлениеКоманды = "") Экспорт
	Если Не КлиентПоддерживаетСинхронныеВызовы() Тогда
		ТекстПредупреждения = НСтр("ru = 'В веб-браузерах Google Chrome и Mozilla Firefox команда ""%1"" недоступна.'");
	Иначе
		ТекстПредупреждения = НСтр("ru = 'Для выполнения команды ""%1"" необходимо
			|установить расширение для работы с 1С:Предприятием.'");
	КонецЕсли;
	Если ЗначениеЗаполнено(ПредставлениеКоманды) Тогда
		ТекстПредупреждения = СтрЗаменить(ТекстПредупреждения, "%1", ПредставлениеКоманды);
	Иначе
		ТекстПредупреждения = СтрЗаменить(ТекстПредупреждения, " ""%1""", "");
	КонецЕсли;
	ВернутьРезультатПослеПоказаПредупреждения(ОбработчикРезультата, ТекстПредупреждения, Неопределено);
КонецПроцедуры

// Сохраняет путь к рабочему каталогу пользователя в настройках.
//
// Параметры:
//  ИмяКаталога - Строка - имя каталога.
//
Процедура УстановитьРабочийКаталогПользователя(ИмяКаталога) Экспорт
	
	РаботаСФайламиСлужебныйВызовСервера.УстановитьРабочийКаталогПользователя(ИмяКаталога);
	
КонецПроцедуры

// Возвращает каталог "Мои Документы" + имя текущего пользователя или
// ранее использованную папку для выгрузки.
//
Функция КаталогВыгрузки() Экспорт
	
	Путь = "";
	
#Если Не ВебКлиент И НЕ МобильныйКлиент Тогда
	
	Путь = ОбщегоНазначенияВызовСервера.ХранилищеОбщихНастроекЗагрузить("ИмяПапкиВыгрузки", "ИмяПапкиВыгрузки");
	
	Если Путь = Неопределено Тогда
		Если Не СтандартныеПодсистемыКлиент.ЭтоБазоваяВерсияКонфигурации() Тогда
			Путь = КаталогМоиДокументы();
			ОбщегоНазначенияВызовСервера.ХранилищеОбщихНастроекСохранить(
				"ИмяПапкиВыгрузки", "ИмяПапкиВыгрузки", Путь);
		КонецЕсли;
	КонецЕсли;
	
#КонецЕсли
	
	Возврат Путь;
	
КонецФункции

// Показывает пользователю диалог выбора файлов и возвращает
// массив - выбранные файлы для импорта.
//
Функция ИмпортируемыеФайлы() Экспорт
	
	ДиалогОткрытияФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
	ДиалогОткрытияФайла.ПолноеИмяФайла     = "";
	ДиалогОткрытияФайла.Фильтр             = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Все файлы (%1)|%1'"), ПолучитьМаскуВсеФайлы());
	ДиалогОткрытияФайла.МножественныйВыбор = Истина;
	ДиалогОткрытияФайла.Заголовок          = НСтр("ru = 'Выберите файлы'");
	
	МассивИменФайлов = Новый Массив;
	
	Если ДиалогОткрытияФайла.Выбрать() Тогда
		МассивФайлов = ДиалогОткрытияФайла.ВыбранныеФайлы;
		
		Для Каждого ИмяФайла Из МассивФайлов Цикл
			МассивИменФайлов.Добавить(ИмяФайла);
		КонецЦикла;
		
	КонецЕсли;
	
	Возврат МассивИменФайлов;
	
КонецФункции

// Проверяет имя файла на наличие некорректных символов.
//
// Параметры:
//  ИмяФайла - Строка- проверяемое имя файла.
//
//  УдалятьНекорректныеСимволы - Булево - Истина указывает удалять некорректные
//             символы из переданной строки.
//
Процедура КорректноеИмяФайла(ИмяФайла, УдалятьНекорректныеСимволы = Ложь) Экспорт
	
	// Перечень запрещенных символов взят отсюда: http://support.microsoft.com/kb/100108/ru
	// при этом были объединены запрещенные символы для файловых систем FAT и NTFS.
	
	СтрИсключения = ОбщегоНазначенияКлиентСервер.ПолучитьНедопустимыеСимволыВИмениФайла();
	
	ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'В имени файла не должно быть следующих символов: %1'"), СтрИсключения);
	
	Результат = Истина;
	
	МассивНайденныхНедопустимыхСимволов =
		ОбщегоНазначенияКлиентСервер.НайтиНедопустимыеСимволыВИмениФайла(ИмяФайла);
	
	Если МассивНайденныхНедопустимыхСимволов.Количество() <> 0 Тогда
		
		Результат = Ложь;
		
		Если УдалятьНекорректныеСимволы Тогда
			ИмяФайла = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(ИмяФайла, "");
		КонецЕсли;
		
	КонецЕсли;
	
	Если Не Результат Тогда
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
КонецПроцедуры

// Рекурсивно обходит каталоги и подсчитывает количество файлов и их суммарный размер.
Процедура ОбходФайловРазмер(Путь, МассивФайлов, РазмерСуммарный, КоличествоСуммарное) Экспорт
	
	Для Каждого ВыбранныйФайл Из МассивФайлов Цикл
		
		Если ВыбранныйФайл.ЭтоКаталог() Тогда
			НовыйПуть = Строка(Путь);
			
			НовыйПуть = НовыйПуть + ПолучитьРазделительПути();
			
			НовыйПуть = НовыйПуть + Строка(ВыбранныйФайл.Имя);
			МассивФайловВКаталоге = НайтиФайлы(НовыйПуть, ПолучитьМаскуВсеФайлы());
			
			Если МассивФайловВКаталоге.Количество() <> 0 Тогда
				ОбходФайловРазмер(
					НовыйПуть, МассивФайловВКаталоге, РазмерСуммарный, КоличествоСуммарное);
			КонецЕсли;
		
			Продолжить;
		КонецЕсли;
		
		РазмерСуммарный = РазмерСуммарный + ВыбранныйФайл.Размер();
		КоличествоСуммарное = КоличествоСуммарное + 1;
		
	КонецЦикла;
	
КонецПроцедуры

// Возвращает путь к каталогу вида
// "C:\Documents and Settings\ИМЯ ПОЛЬЗОВАТЕЛЯ\Application Data\1C\ФайлыА8\".
//
Функция ВыбратьПутьККаталогуДанныхПользователя() Экспорт
	
	ИмяКаталога = "";
	Если РасширениеРаботыСФайламиПодключено() Тогда
		ИмяКаталога = РабочийКаталогДанныхПользователя();
	КонецЕсли;
	
	Возврат ИмяКаталога;
	
КонецФункции

// Открывает Проводник Windows и выделяет указанный файл.
Функция ОткрытьПроводникСФайлом(Знач ПолноеИмяФайла) Экспорт
	
	ФайлНаДиске = Новый Файл(ПолноеИмяФайла);
	
	Если НЕ ФайлНаДиске.Существует() Тогда
		Возврат Ложь;
	КонецЕсли;
	
	ФайловаяСистемаКлиент.ОткрытьПроводник(ФайлНаДиске.ПолноеИмя);
	
	Возврат Истина;
	
КонецФункции

// Возвращает результат подключения расширения для работы с 1С:Предприятием.
//
//  Возвращаемое значение:
//   Булево - в тонком клиенте всегда Истина, в браузере Google Chrome всегда ложь.
//
Функция РасширениеРаботыСФайламиПодключено() Экспорт
	Если КлиентПоддерживаетСинхронныеВызовы() Тогда
		Возврат ПодключитьРасширениеРаботыСФайлами();
	Иначе
		Возврат Ложь;
	КонецЕсли;
КонецФункции

// Описание процедуры см. ОбщегоНазначенияКлиент.ПоказатьВопросОбУстановкеРасширенияРаботыСФайлами.
//
Процедура ПоказатьВопросОбУстановкеРасширенияРаботыСФайлами(ОписаниеОповещения) Экспорт
	Если Не КлиентПоддерживаетСинхронныеВызовы() Тогда
		ВыполнитьОбработкуОповещения(ОписаниеОповещения, Ложь);
	Иначе
		ФайловаяСистемаКлиент.ПодключитьРасширениеДляРаботыСФайлами(ОписаниеОповещения);
	КонецЕсли;
КонецПроцедуры

Процедура ОтправитьФайлыПоПочте(МассивФайлов, ИдентификаторФормы, ПараметрыОтправки, ЭтоФайл = Ложь) Экспорт
	
	Если МассивФайлов.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	Параметры = Новый Структура;
	Параметры.Вставить("МассивФайлов", МассивФайлов);
	Параметры.Вставить("ИдентификаторФормы", ИдентификаторФормы);
	Параметры.Вставить("ЭтоФайл", ЭтоФайл);
	Параметры.Вставить("ПараметрыОтправки", ПараметрыОтправки);
	
	ОписаниеОповещения = Новый ОписаниеОповещения("ОтправитьФайлыПоПочтеНастройкаУчетнойЗаписиПредложена", ЭтотОбъект, Параметры);
	Если ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСПочтовымиСообщениями") Тогда
		МодульРаботаСПочтовымиСообщениямиКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("РаботаСПочтовымиСообщениямиКлиент");
		МодульРаботаСПочтовымиСообщениямиКлиент.ПроверитьНаличиеУчетнойЗаписиДляОтправкиПочты(ОписаниеОповещения);
	КонецЕсли;
	
КонецПроцедуры

Процедура ОтправитьФайлыПоПочтеНастройкаУчетнойЗаписиПредложена(УчетнаяЗаписьНастроена, ДополнительныеПараметры) Экспорт
	
	Если УчетнаяЗаписьНастроена <> Истина Тогда
		Возврат;
	КонецЕсли;
	
	СписокВложений = РаботаСФайламиСлужебныйВызовСервера.ПоместитьФайлыВоВременноеХранилище(ДополнительныеПараметры);
	ПараметрыОтправки = ДополнительныеПараметры.ПараметрыОтправки;
	
	ПараметрыОтправки.Вставить("Вложения", СписокВложений);
	ПараметрыОтправки.Вставить("УдалятьФайлыПослеОтправки", Истина);
	
	МодульРаботаСПочтовымиСообщениямиКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("РаботаСПочтовымиСообщениямиКлиент");
	МодульРаботаСПочтовымиСообщениямиКлиент.СоздатьНовоеПисьмо(ПараметрыОтправки);
	
КонецПроцедуры

Функция ПараметрыОбновленияФайла(ОбработчикРезультата, ОбъектСсылка, ИдентификаторФормы) Экспорт
	
	ПараметрыОбработчика = Новый Структура;
	ПараметрыОбработчика.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыОбработчика.Вставить("ОбъектСсылка", ОбъектСсылка);
	ПараметрыОбработчика.Вставить("ИдентификаторФормы", ИдентификаторФормы);
	ПараметрыОбработчика.Вставить("ХранитьВерсии");
	ПараметрыОбработчика.Вставить("ФайлРедактируетТекущийПользователь");
	ПараметрыОбработчика.Вставить("Редактирует");
	ПараметрыОбработчика.Вставить("АвторТекущейВерсии");
	ПараметрыОбработчика.Вставить("ПереданныйПолныйПутьКФайлу", "");
	ПараметрыОбработчика.Вставить("СоздатьНовуюВерсию");
	ПараметрыОбработчика.Вставить("КомментарийКВерсии");
	ПараметрыОбработчика.Вставить("ПоказыватьОповещение", Истина);
	ПараметрыОбработчика.Вставить("ПрименитьКоВсем", Ложь);
	ПараметрыОбработчика.Вставить("ОсвобождатьФайлы", Истина);
	ПараметрыОбработчика.Вставить("Кодировка");
	Возврат ПараметрыОбработчика;
	
КонецФункции	

// Нажатие команды "Показывать служебные файлы" в списке файлов.
//
// Параметры:
//  Список - ДинамическийСписок
//
// Возвращаемое значение:
//  Булево - отображение служебных файлов в списке.
//
Функция ПоказыватьСлужебныеФайлыНажатие(Список) Экспорт
	
	ЭлементОтбора = ОбщегоНазначенияКлиентСервер.НайтиЭлементОтбораПоПредставлению(Список.Отбор.Элементы, "СкрыватьСлужебные");
	Если ЭлементОтбора = Неопределено Тогда
		Возврат Ложь;
	КонецЕсли;
	
	ПоказыватьСлужебныеФайлы = ЭлементОтбора.Использование;
	ЭлементОтбора.Использование = Не ПоказыватьСлужебныеФайлы;
	Возврат ПоказыватьСлужебныеФайлы;
	
КонецФункции

// Сохраняет отредактированный файл в ИБ и снимает с него блокировку.
//
// Параметры:
//   Параметры - см. ПараметрыОбновленияФайла.
//
Процедура ЗакончитьРедактированиеСОповещением(Параметры) Экспорт
	
	Если Параметры.ОбъектСсылка = Неопределено Тогда
		ВернутьРезультат(Параметры.ОбработчикРезультата, Неопределено);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", Параметры.ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("ПараметрКоманды", Параметры.ОбъектСсылка);
	Обработчик = Новый ОписаниеОповещения("ЗакончитьРедактированиеСОповещениемЗавершение", ЭтотОбъект, ПараметрыВыполнения);
	
	ПараметрыОбработчика = ПараметрыОбновленияФайла(Обработчик, Параметры.ОбъектСсылка, Параметры.ИдентификаторФормы);
	ПараметрыОбработчика.СоздатьНовуюВерсию = Параметры.СоздатьНовуюВерсию;
	ЗакончитьРедактирование(ПараметрыОбработчика);
	
КонецПроцедуры

// Сохраняет файл в информационной базе, но не освобождает его.
Процедура СохранитьИзмененияФайлаСОповещением(ОбработчикРезультата, ПараметрКоманды, ИдентификаторФормы) Экспорт
	
	Если ПараметрКоманды = Неопределено Тогда
		ВернутьРезультат(ОбработчикРезультата, Неопределено);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("ПараметрКоманды", ПараметрКоманды);
	
	Обработчик = Новый ОписаниеОповещения("СохранитьИзмененияФайлаСОповещениемЗавершение", ЭтотОбъект, ПараметрыВыполнения);
	ПараметрыОбработчика = ПараметрыОбновленияФайла(Обработчик, ПараметрКоманды, ИдентификаторФормы);
	СохранитьИзмененияФайла(ПараметрыОбработчика);
	
КонецПроцедуры

// Возвращает строковое представление расширений, ассоциированных с типом файла.
//
// Параметры:
//   ТипФайла - Строка - типы файлов см. ЗаполнитьСписокТипамиФайлов.
//
Функция РасширенияПоТипуФайла(ТипФайла) Экспорт
	
	Если ТипФайла = "Изображения" Тогда
		Возврат "JPG JPEG JP2 JPG2 PNG BMP TIFF";
	ИначеЕсли ТипФайла = "ОфисныеДокументы" Тогда
		Возврат "DOC DOCX DOCM DOT DOTX DOTM XLS XLSX XLSM XLT XLTM XLSB PPT PPTX PPTM PPS PPSX PPSM POT POTX POTM"
			+ "ODT OTT ODP OTP ODS OTS ODC OTC ODF OTF ODM OTH SDW STW SXW STC SXC SDC SDD STI";
	Иначе
		Возврат "";
	КонецЕсли;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Процедуры и функции работы с криптографией.

// Проверить подписи данных объекта в таблице.
// 
// Параметры:
//  Форма - ФормаКлиентскогоПриложения - с реквизитами:
//    * Объект - ДанныеФормыСтруктура - как у объекта со свойствами Ссылка, Зашифрован.
//                  Например, СправочникОбъект.Файл, СправочникОбъект.ДокументПрисоединенныеФайлы.
//               Если свойств у объекта нет, то структуру со свойствами нужно передать в ДанныеФайла.
//
//    * ЭлектронныеПодписи - ДанныеФормыКоллекция:
//       * ДатаПроверкиПодписи - Дата - возвращаемое значение. Дата проверки.
//       * Статус              - Строка - возвращаемое значение. Результат проверки.
//       * АдресПодписи        - Строка - адрес данных подписи во временном хранилище.
//
//  СсылкаНаДвоичныеДанные - ДвоичныеДанные - двоичные данные файла.
//                         - Строка - адрес во временном хранилище или навигационная ссылка.
//
//  ВыделенныеСтроки - Массив - свойство таблицы формы параметра ЭлектронныеПодписи.
//                   - Неопределено - проверить все подписи.
//  ДанныеФайла      - см. РаботаСФайлами.ДанныеФайла
//
Процедура ПроверитьПодписи(Форма, СсылкаНаДвоичныеДанные, ВыделенныеСтроки = Неопределено, ДанныеФайла = Неопределено) Экспорт
	
	// 1. Получаем адрес двоичных данных, адреса двоичных данных подписей.
	// 2. Если файл зашифрован, то расшифровываем, далее выполняем проверку.
	
	Если ДанныеФайла = Неопределено Тогда
		ДанныеФайла = Форма.Объект; // ОпределяемыйТип.ПрисоединенныйФайлОбъект
	КонецЕсли;
	
	ДополнительныеПараметры = Новый Структура;
	ДополнительныеПараметры.Вставить("Форма", Форма);
	ДополнительныеПараметры.Вставить("ВыделенныеСтроки", ВыделенныеСтроки);
	ДополнительныеПараметры.Вставить("ПодписанныйОбъект", ДанныеФайла.Ссылка);
	ДополнительныеПараметры.Вставить("СтрокиДляПроверкиПоМЧД", Новый Массив);
	
	Если Не ДанныеФайла.Зашифрован Тогда
		ПроверитьПодписиПослеПодготовкиДанных(СсылкаНаДвоичныеДанные, ДополнительныеПараметры);
		Возврат;
	КонецЕсли;
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		Возврат;
	КонецЕсли;
	
	ОписаниеДанных = Новый Структура;
	ОписаниеДанных.Вставить("Операция",              НСтр("ru = 'Расшифровка файла'"));
	ОписаниеДанных.Вставить("ЗаголовокДанных",       НСтр("ru = 'Файл'"));
	ОписаниеДанных.Вставить("Данные",                СсылкаНаДвоичныеДанные);
	ОписаниеДанных.Вставить("Представление",         ДанныеФайла.Ссылка);
	ОписаниеДанных.Вставить("СертификатыШифрования", ДанныеФайла.Ссылка);
	ОписаниеДанных.Вставить("СообщитьОЗавершении",   Ложь);
	
	ОбработчикПродолжения = Новый ОписаниеОповещения("ПослеРасшифровкиФайлаПриПроверкеПодписи", ЭтотОбъект, ДополнительныеПараметры);
	
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	МодульЭлектроннаяПодписьКлиент.Расшифровать(ОписаниеДанных, , ОбработчикПродолжения);
	
КонецПроцедуры

// Продолжение процедуры ПроверитьПодписи.
Процедура ПроверитьПодписиПослеПроверкиСтроки(РезультатПроверкиПодписи, ДополнительныеПараметры) Экспорт
	
	Результат = РезультатПроверкиПодписи.Результат;
	СтрокаПодписи = ДополнительныеПараметры.СтрокаПодписи;
	
	ДанныеСтроки = ДанныеСтрокиПодписи();
	ЗаполнитьЗначенияСвойств(ДанныеСтроки, СтрокаПодписи);
	
	ДанныеСтроки.ДатаПроверкиПодписи = ОбщегоНазначенияКлиент.ДатаСеанса();
	ДанныеСтроки.ПодписьВерна      = (Результат = Истина);
	ДанныеСтроки.ТребуетсяПроверка = РезультатПроверкиПодписи.ТребуетсяПроверка;
	ДанныеСтроки.ОписаниеОшибки    = ?(ДанныеСтроки.ПодписьВерна, "", Результат);
	Если ЗначениеЗаполнено(РезультатПроверкиПодписи.ТипПодписи) Тогда
		ДанныеСтроки.ТипПодписи        = РезультатПроверкиПодписи.ТипПодписи;
	КонецЕсли;
	Если ЗначениеЗаполнено(РезультатПроверкиПодписи.СрокДействияПоследнейМеткиВремени) Тогда
		ДанныеСтроки.СрокДействияПоследнейМеткиВремени = РезультатПроверкиПодписи.СрокДействияПоследнейМеткиВремени;
	КонецЕсли;
	
	// Локализация
	Если ЗначениеЗаполнено(ДанныеСтроки.РезультатПроверкиПодписиПоМЧД)
		И ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.МашиночитаемыеДоверенности") Тогда
		
		Структура = Новый Структура;
		Структура.Вставить("Сертификат", РезультатПроверкиПодписи.Сертификат);
		Структура.Вставить("ДатаПодписи", ДанныеСтроки.ДатаПодписи);
		Структура.Вставить("Индекс", ДополнительныеПараметры.Индекс);
		Структура.Вставить("РезультатПроверкиПодписиПоМЧД", ДанныеСтроки.РезультатПроверкиПодписиПоМЧД);
		
		ДополнительныеПараметры.СтрокиДляПроверкиПоМЧД.Добавить(Структура);
	КонецЕсли;
	// Конец Локализация
	
	РаботаСФайламиСлужебныйКлиентСервер.ЗаполнитьСтатусПодписи(ДанныеСтроки, ОбщегоНазначенияКлиент.ДатаСеанса());
	
	ЗаполнитьЗначенияСвойств(СтрокаПодписи, ДанныеСтроки);
	
	ПроверитьПодписиЦиклНачало(ДополнительныеПараметры);
	
КонецПроцедуры

Процедура ПродлитьДействиеПодписей(Форма, ПараметрыПродления, ОбработчикПродолжения) Экспорт
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		Возврат;
	КонецЕсли;

	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	МодульЭлектроннаяПодписьКлиент.ОткрытьФормуПродленияДействияПодписей(
		Форма, ПараметрыПродления, ОбработчикПродолжения);
		
КонецПроцедуры


// Для формы файла.
//
// Параметры:
//   Форма - ФормаКлиентскогоПриложения
//   ЭтоНовый - Булево - файл не записан
//
Процедура УстановитьДоступностьКомандСпискаЭлектронныхПодписей(Форма, ЭтоНовый) Экспорт
	
	Элементы = Форма.Элементы;
	ЕстьПодписи = (Форма.ЭлектронныеПодписи.Количество() <> 0);
	
	ЭлектронныеПодписиОткрыть = Элементы.ЭлектронныеПодписиОткрыть; // КнопкаФормы
	ЭлектронныеПодписиОткрыть.Доступность = ЕстьПодписи;
	
	ЭлектронныеПодписиПроверить = Элементы.ЭлектронныеПодписиПроверить; // КнопкаФормы
	ЭлектронныеПодписиПроверить.Доступность = ЕстьПодписи И Не ЭтоНовый;
	
	ЭлектронныеПодписиПроверитьВсе = Элементы.ЭлектронныеПодписиПроверитьВсе; // КнопкаФормы
	ЭлектронныеПодписиПроверитьВсе.Доступность = ЕстьПодписи И Не ЭтоНовый;
	
	ЭлектронныеПодписиСохранить = Элементы.ЭлектронныеПодписиСохранить; // КнопкаФормы
	ЭлектронныеПодписиСохранить.Доступность = ЕстьПодписи;
	
	ЭлектронныеПодписиУдалить = Элементы.ЭлектронныеПодписиУдалить; // КнопкаФормы
	ЭлектронныеПодписиУдалить.Доступность = ЕстьПодписи И Не ЭтоНовый;
	
	ЭлектронныеПодписиПродлитьДействиеПодписей = Элементы.ЭлектронныеПодписиПродлитьДействиеПодписей; // КнопкаФормы
	ЭлектронныеПодписиПродлитьДействиеПодписей.Доступность = ЕстьПодписи И Не ЭтоНовый;
	
КонецПроцедуры

// Для формы файла.
//
// Параметры:
//   Форма - ФормаКлиентскогоПриложения
//
Процедура УстановитьДоступностьКомандСпискаСертификатовШифрования(Форма) Экспорт
	
	Объект   = Форма.Объект;
	Элементы = Форма.Элементы;
	
	СертификатыШифрованияОткрыть = Элементы.СертификатыШифрованияОткрыть; // КнопкаФормы
	СертификатыШифрованияОткрыть.Доступность = Объект.Зашифрован;
	
КонецПроцедуры

#Область Сканирование


// Открывает диалог сканирования и просмотра картинки.
// 
// Параметры:
//  ПараметрыВыполнения - Структура:
//   * ОбработчикРезультата - Неопределено, ОписаниеОповещения.
//   * ВладелецФайла - Неопределено, ОпределяемыйТип.ВладелецФайлов.
//   * ФормаВладелец - Неопределено, Форма.
//   * ЭтоФайл - Булево.
//  ПараметрыСканирования - см. РаботаСФайламиКлиент.ПараметрыСканирования.
//
Процедура ДобавитьСоСканера(ПараметрыВыполнения, ПараметрыСканирования = Неопределено) Экспорт
	
#Если МобильныйКлиент Тогда
	
	ТипРезультата = ПараметрыВыполнения.ТипРезультата;
	
	ДанныеМультимедиа = СредстваМультимедиа.СделатьФотоснимок();
	Если ДанныеМультимедиа = Неопределено Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
		Возврат;
	КонецЕсли;
	
	ИмяБезРасширения = "img_" + Формат(ОбщегоНазначенияКлиент.ДатаСеанса(), "ДФ=yyyyMMdd_hhmmss");
	
	РезультатСканирования = РезультатСканирования();
		
	Если ТипРезультата = РаботаСФайламиКлиент.ТипРезультатаКонвертацииДвоичныеДанные() Тогда
		РезультатСканирования.ДвоичныеДанные = ДанныеМультимедиа.ПолучитьДвоичныеДанные();
		ВыполнитьОбработкуОповещения(ПараметрыВыполнения.ОбработчикРезультата, РезультатСканирования);
	ИначеЕсли ТипРезультата = РаботаСФайламиКлиент.ТипРезультатаКонвертацииИмяФайла() Тогда
		ДанныеИзображения = ДанныеМультимедиа.ПолучитьДвоичныеДанные();
		// АПК:441-выкл Является результатом метода
		ИмяВременногоФайла = ПолучитьИмяВременногоФайла(ДанныеМультимедиа.РасширениеФайла);
		// АПК:441-вкл
		ДанныеИзображения.Записать(ИмяВременногоФайла);
		РезультатСканирования.ИмяФайла = ИмяВременногоФайла;
		
		ВыполнитьОбработкуОповещения(ПараметрыВыполнения.ОбработчикРезультата, РезультатСканирования);
	Иначе
		
		ПараметрыФайла = РаботаСФайламиСлужебныйКлиентСервер.ПараметрыДобавленияФайла();
		ПараметрыФайла.ВладелецФайлов = ПараметрыВыполнения.ВладелецФайла;
		ПараметрыФайла.ИмяБезРасширения = ИмяБезРасширения;
		ПараметрыФайла.РасширениеБезТочки = ДанныеМультимедиа.РасширениеФайла;
		
		АдресФайла = ПоместитьВоВременноеХранилище(ДанныеМультимедиа.ПолучитьДвоичныеДанные(),
			ПараметрыВыполнения.ФормаВладелец.УникальныйИдентификатор);
			
		РезультатСканирования.Вставить("ФайлДобавлен", Истина);
		РезультатСканирования.Вставить("ФайлСсылка", РаботаСФайламиСлужебныйВызовСервера.ДобавитьФайл(ПараметрыФайла, АдресФайла));
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, РезультатСканирования);
	КонецЕсли;
	
#Иначе
	
	ИдентификаторКлиента = ИдентификаторКлиента();
	
	Если ПараметрыСканирования = Неопределено Тогда
		ПараметрыСканирования = РаботаСФайламиКлиент.ПараметрыСканирования(Истина);
	КонецЕсли;
	
	ПараметрыФормы = Новый Структура("ВладелецФайла, ЭтоФайл, НеОткрыватьКарточкуПослеСозданияИзФайла, ТолькоОдинФайл, ТипРезультата");
	ЗаполнитьЗначенияСвойств(ПараметрыФормы, ПараметрыВыполнения);
	ПараметрыФормы.Вставить("ИдентификаторКлиента", ИдентификаторКлиента);
	ПараметрыФормы.Вставить("ПараметрыСканирования", ПараметрыСканирования);
	
	ОписаниеОповещенияОЗакрытии = ОбработчикЗавершения(ПараметрыВыполнения.ОбработчикРезультата);
	ОткрытьФорму("Обработка.Сканирование.Форма.РезультатСканирования", ПараметрыФормы, 
		ПараметрыВыполнения.ФормаВладелец, , , , ОписаниеОповещенияОЗакрытии);
	
#КонецЕсли
	
КонецПроцедуры

Функция РезультатСканирования() Экспорт
	Результат = Новый Структура;
	Результат.Вставить("ТекстОшибки", "");
	Результат.Вставить("ФайлДобавлен", Ложь);
	Результат.Вставить("ФайлСсылка");	
	Результат.Вставить("ДвоичныеДанные");
	Результат.Вставить("ИмяФайла");
	Возврат Результат;
КонецФункции

Функция ИдентификаторКлиента() Экспорт
	СистемнаяИнформация = Новый СистемнаяИнформация();
	Возврат СистемнаяИнформация.ИдентификаторКлиента;
КонецФункции

#КонецОбласти

////////////////////////////////////////////////////////////////////////////////
// Общие процедуры и функции работы с файлами операционной системы.

// Открыть версию файла.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  ДанныеФайла             - Структура
//  УникальныйИдентификатор - УникальныйИдентификатор формы.
//
Процедура ОткрытьВерсиюФайла(ОбработчикРезультата, ДанныеФайла, УникальныйИдентификатор = Неопределено) Экспорт
	
	ПараметрыОбработчика = Новый Структура;
	ПараметрыОбработчика.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыОбработчика.Вставить("ДанныеФайла", ДанныеФайла);
	ПараметрыОбработчика.Вставить("УникальныйИдентификатор", УникальныйИдентификатор);
	
	Обработчик = Новый ОписаниеОповещения("ОткрытьВерсиюФайлаПослеУстановкиРасширения", ЭтотОбъект, ПараметрыОбработчика);
	
	ПоказатьВопросОбУстановкеРасширенияРаботыСФайлами(Обработчик);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистем конфигурации.

// См. ОбщегоНазначенияКлиентПереопределяемый.ПередЗавершениемРаботыСистемы
Процедура ПередЗавершениемРаботыСистемы(Отказ, Предупреждения) Экспорт
	
	Ответ = ПроверитьЗанятыеФайлыПриЗавершенииРаботы();
	Если Ответ = Неопределено Тогда 
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(Ответ) <> Тип("Структура") Тогда
		Возврат;
	КонецЕсли;
	
	ПредупреждениеПользователю = СтандартныеПодсистемыКлиент.ПредупреждениеПриЗавершенииРаботы();
	ПредупреждениеПользователю.ТекстГиперссылки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Открыть список редактируемых файлов (%1)'"),
		Ответ.КоличествоЗанятыхФайлов);
	ПредупреждениеПользователю.ТекстПредупреждения = НСтр("ru = 'Имеются занятые для редактирования файлы'");
	
	ДействиеПриНажатииГиперссылки = ПредупреждениеПользователю.ДействиеПриНажатииГиперссылки;
	
	ПрикладнаяФормаПредупреждения = Неопределено;
	Ответ.Свойство("ПрикладнаяФормаПредупреждения", ПрикладнаяФормаПредупреждения);
	ПараметрыПрикладнойФормыПредупреждения = Неопределено;
	Ответ.Свойство("ПараметрыПрикладнойФормыПредупреждения", ПараметрыПрикладнойФормыПредупреждения);
	
	Форма = Неопределено;
	Ответ.Свойство("Форма", Форма);
	ПараметрыФормы = Неопределено;
	Ответ.Свойство("ПараметрыФормы", ПараметрыФормы);
	
	Если ПрикладнаяФормаПредупреждения <> Неопределено Тогда 
		ДействиеПриНажатииГиперссылки.ПрикладнаяФормаПредупреждения = ПрикладнаяФормаПредупреждения;
		ДействиеПриНажатииГиперссылки.ПараметрыПрикладнойФормыПредупреждения = ПараметрыПрикладнойФормыПредупреждения;
	КонецЕсли;
	Если Форма <> Неопределено Тогда 
		ДействиеПриНажатииГиперссылки.Форма = Форма;
		ДействиеПриНажатииГиперссылки.ПараметрыФормы = ПараметрыФормы;
	КонецЕсли;
	
	Предупреждения.Добавить(ПредупреждениеПользователю);
	
КонецПроцедуры

Функция ПараметрыОповещенияЗаписиФайла(Событие = "") Экспорт
	ПараметрыСобытия = Новый Структура;
	ПараметрыСобытия.Вставить("Событие", Событие);
	ПараметрыСобытия.Вставить("ЭтоНовый", Ложь);
	ПараметрыСобытия.Вставить("Владелец");
	ПараметрыСобытия.Вставить("Файл");
	Возврат ПараметрыСобытия;
КонецФункции

Процедура ОповеститьОбИзмененииФайлов(Файлы, ПараметрыОповещенияЗаписиФайла = Неопределено) Экспорт
	Если ТипЗнч(Файлы) <> Тип("Массив") Тогда
		ФайлыДляОповещения = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Файлы);
	Иначе
		ФайлыДляОповещения = Файлы;
	КонецЕсли;
	
	Если ПараметрыОповещенияЗаписиФайла = Неопределено Тогда
		ПараметрыОповещенияЗаписиФайла = ПараметрыОповещенияЗаписиФайла();
	КонецЕсли;
	
	Для Каждого Файл Из ФайлыДляОповещения Цикл
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла, Файл);
	КонецЦикла;
	
КонецПроцедуры

#Область ИзвлечениеТекста

Процедура ИзвлечьТекстВерсии(ФайлИлиВерсияФайла, АдресФайла, Расширение, УникальныйИдентификатор,
	Кодировка = Неопределено) Экспорт

#Если НЕ ВебКлиент Тогда
	ИмяФайлаСПутем = ПолучитьИмяВременногоФайла(Расширение);
	
	Если Не ПолучитьФайл(АдресФайла, ИмяФайлаСПутем, Ложь) Тогда
		Возврат;
	КонецЕсли;
	
	// Для варианта с хранением файлов в томах удаляем файл из временного хранилища после получения.
	Если ЭтоАдресВременногоХранилища(АдресФайла) Тогда
		УдалитьИзВременногоХранилища(АдресФайла);
	КонецЕсли;
	
	РезультатИзвлечения = "НеИзвлечен";
	АдресВременногоХранилищаТекста = "";
	
	Текст = "";
	Если ИмяФайлаСПутем <> "" Тогда
		
		// Извлечение текста из файла.
		Отказ = Ложь;
		Текст = ИзвлечьТекст(ИмяФайлаСПутем, Отказ, Кодировка);
		
		Если Отказ = Ложь Тогда
			РезультатИзвлечения = "Извлечен";
			
			Если Не ПустаяСтрока(Текст) Тогда
				ИмяВременногоФайла = ПолучитьИмяВременногоФайла();
				ТекстовыйФайл = Новый ЗаписьТекста(ИмяВременногоФайла, КодировкаТекста.UTF8);
				ТекстовыйФайл.Записать(Текст);
				ТекстовыйФайл.Закрыть();
				
				РезультатЗагрузки = ПоместитьФайлСДискаВоВременноеХранилище(ИмяВременногоФайла, , УникальныйИдентификатор);
				Если РезультатЗагрузки <> Неопределено Тогда
					АдресВременногоХранилищаТекста = РезультатЗагрузки;
				КонецЕсли;
				
				Попытка
					УдалитьФайлы(ИмяВременногоФайла);
				Исключение
					ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
						"Предупреждение", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()),, Истина);
				КонецПопытки;	
			КонецЕсли;
		Иначе
			// Когда Текст извлечь "некому" - это нормальный случай,
			// сообщение об ошибке не формируется.
			РезультатИзвлечения = "ИзвлечьНеУдалось";
		КонецЕсли;
		
	КонецЕсли;
	
	Попытка
		УдалитьФайлы(ИмяФайлаСПутем);
	Исключение
		ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
			"Предупреждение", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()),, Истина);
	КонецПопытки;	
	
	РаботаСФайламиСлужебныйВызовСервера.ЗаписатьРезультатИзвлеченияТекста(
		ФайлИлиВерсияФайла, РезультатИзвлечения, АдресВременногоХранилищаТекста);
		
#КонецЕсли

КонецПроцедуры

#КонецОбласти

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Процедура УстановитьУниверсальноеВремяИзменения(ПутьКФайлу, НовоеВремяИзменения)
	Если НЕ ЗначениеЗаполнено(НовоеВремяИзменения) Тогда
		Возврат;
	КонецЕсли;
	
	Файл = Новый Файл(ПутьКФайлу);
	Если Файл.Существует() Тогда
		Файл.УстановитьУниверсальноеВремяИзменения(НовоеВремяИзменения);
	КонецЕсли;
КонецПроцедуры

// Возвращает Истина, если файл с таким расширением можно загружать.
Функция ПроверитьРасширениеФайлаДляЗагрузки(РасширениеФайла, ВызыватьИсключение = Истина)
	
	ОбщиеНастройки = ОбщиеНастройкиРаботыСФайлами();
	Если НЕ ОбщиеНастройки.ЗапретЗагрузкиФайловПоРасширению Тогда
		Возврат Истина;
	КонецЕсли;
	
	Если РаботаСФайламиСлужебныйКлиентСервер.РасширениеФайлаВСписке(
		ОбщиеНастройки.СписокЗапрещенныхРасширений, РасширениеФайла) Тогда
		
		Если ВызыватьИсключение Тогда
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Загрузка файлов с расширением ""%1"" запрещена.
				           |Обратитесь к администратору.'"),
				РасширениеФайла);
		Иначе
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

// Извлечь текст из файла и возвратить его в виде строки.
Функция ИзвлечьТекст(ПолноеИмяФайла, Отказ = Ложь, Кодировка = Неопределено)
	
	ИзвлеченныйТекст = "";
	
	Попытка
		Файл = Новый Файл(ПолноеИмяФайла);
		Если Не Файл.Существует() Тогда
			Отказ = Истина;
			Возврат ИзвлеченныйТекст;
		КонецЕсли;
	Исключение
		Отказ = Истина;
		Возврат ИзвлеченныйТекст;
	КонецПопытки;
	
	Прекратить = Ложь;
	ОбщиеНастройки = ОбщиеНастройкиРаботыСФайлами();
	
#Если Не ВебКлиент И НЕ МобильныйКлиент Тогда
	
	РасширениеИмениФайла =
		ОбщегоНазначенияКлиентСервер.ПолучитьРасширениеИмениФайла(ПолноеИмяФайла);
	
	РасширениеФайлаВСписке = РаботаСФайламиСлужебныйКлиентСервер.РасширениеФайлаВСписке(
		ОбщиеНастройки.СписокРасширенийТекстовыхФайлов, РасширениеИмениФайла);
	
	Если РасширениеФайлаВСписке Тогда
		Возврат РаботаСФайламиСлужебныйКлиентСервер.ИзвлечьТекстИзТекстовогоФайла(
			ПолноеИмяФайла, Кодировка, Отказ);
	КонецЕсли;
	
	Попытка
		Извлечение = Новый ИзвлечениеТекста(ПолноеИмяФайла);
		ИзвлеченныйТекст = Извлечение.ПолучитьТекст();
	Исключение
		// Когда текст некому извлечь исключение не требуется. Это нормальный случай.
		ИзвлеченныйТекст = "";
		Прекратить = Истина;
	КонецПопытки;
		
#КонецЕсли
	
	Если ПустаяСтрока(ИзвлеченныйТекст) Тогда
		
		РасширениеИмениФайла =
			ОбщегоНазначенияКлиентСервер.ПолучитьРасширениеИмениФайла(ПолноеИмяФайла);
		
		РасширениеФайлаВСписке = РаботаСФайламиСлужебныйКлиентСервер.РасширениеФайлаВСписке(
			ОбщиеНастройки.СписокРасширенийФайловOpenDocument, РасширениеИмениФайла);
		
		Если РасширениеФайлаВСписке Тогда
			Возврат РаботаСФайламиСлужебныйКлиентСервер.ИзвлечьТекстOpenDocument(ПолноеИмяФайла, Отказ);
		КонецЕсли;
		
	КонецЕсли;
	
	Если Прекратить Тогда
		Отказ = Истина;
	КонецЕсли;
	
	Возврат ИзвлеченныйТекст;
	
КонецФункции

// Возвращает путь к рабочему каталогу данных пользователя. Этот каталог используется
// в качестве начального значения для рабочего каталога пользователя.
//
// Параметры:
//  Оповещение - ОписаниеОповещения - оповещение, которое выполняется после получения рабочего
//   каталога пользователя. В качестве результата возвращается Структура со свойствами:
//     * Каталог        - Строка - полное имя рабочего каталога данных пользователя.
//     * ОписаниеОшибки - Строка - текст ошибки, если каталог получить не удалось.
//
Процедура ПолучитьРабочийКаталогДанныхПользователя(Оповещение)
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение", Оповещение);
	
	НачатьПолучениеРабочегоКаталогаДанныхПользователя(Новый ОписаниеОповещения(
		"ПолучитьРабочийКаталогДанныхПользователяПослеПолучения", ЭтотОбъект, Контекст,
		"ПолучитьРабочийКаталогДанныхПользователяПослеОшибкиПолучения", ЭтотОбъект));
	
КонецПроцедуры

// Продолжение процедуры ПолучитьРабочийКаталогДанныхПользователя.
Процедура ПолучитьРабочийКаталогДанныхПользователяПослеОшибкиПолучения(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	Результат = Новый Структура;
	Результат.Вставить("Каталог", "");
	Результат.Вставить("ОписаниеОшибки", СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Не удалось получить рабочий каталог данных пользователя по причине:
		           |%1'"), ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке)));
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьРабочийКаталогДанныхПользователя.
Процедура ПолучитьРабочийКаталогДанныхПользователяПослеПолучения(КаталогДанныхПользователя, Контекст) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Каталог", КаталогДанныхПользователя);
	Результат.Вставить("ОписаниеОшибки", "");
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
	
КонецПроцедуры

// Продолжение процедуры ПроверитьПодписи.
Процедура ПроверитьПодписиЦиклНачало(ДополнительныеПараметры)
	
	Если ДополнительныеПараметры.Коллекция.Количество() <= ДополнительныеПараметры.Индекс + 1 Тогда
		
		// Локализация
		
		Если ДополнительныеПараметры.СтрокиДляПроверкиПоМЧД.Количество() > 0 Тогда
			Результат = РаботаСФайламиСлужебныйВызовСервера.ПроверитьПодписиПоМЧД(
				ДополнительныеПараметры.СтрокиДляПроверкиПоМЧД, ДополнительныеПараметры.ПодписанныйОбъект);
			Для Каждого РезультатПроверки Из Результат Цикл
				Элемент = ДополнительныеПараметры.Коллекция[РезультатПроверки.Индекс];
				СтрокаПодписи = ?(ТипЗнч(Элемент) <> Тип("Число"), Элемент,
					ДополнительныеПараметры.Форма.ЭлектронныеПодписи.НайтиПоИдентификатору(Элемент));
				ЗаполнитьЗначенияСвойств(СтрокаПодписи, РезультатПроверки);
			КонецЦикла;
		КонецЕсли;
		
		// Конец Локализация
		
		Возврат;
	КонецЕсли;
	
	ДополнительныеПараметры.Индекс = ДополнительныеПараметры.Индекс + 1;
	Элемент = ДополнительныеПараметры.Коллекция[ДополнительныеПараметры.Индекс];
	
	ДополнительныеПараметры.Вставить("СтрокаПодписи", ?(ТипЗнч(Элемент) <> Тип("Число"), Элемент,
		ДополнительныеПараметры.Форма.ЭлектронныеПодписи.НайтиПоИдентификатору(Элемент)));
	
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	ПараметрыПроверкиПодписи = МодульЭлектроннаяПодписьКлиент.ПараметрыПроверкиПодписи();
	ПараметрыПроверкиПодписи.РезультатВВидеСтруктуры = Истина;
	
	МодульЭлектроннаяПодписьКлиент.ПроверитьПодпись(
		Новый ОписаниеОповещения("ПроверитьПодписиПослеПроверкиСтроки", ЭтотОбъект, ДополнительныеПараметры),
		ДополнительныеПараметры.Данные,
		ДополнительныеПараметры.СтрокаПодписи.АдресПодписи,
		Неопределено,
		ДополнительныеПараметры.СтрокаПодписи.ДатаПодписи, ПараметрыПроверкиПодписи);
	
КонецПроцедуры

// Проверяет свойства файла в рабочем каталоге и в хранилище файлов,
// если требуется уточняет у пользователя и возвращает одно из действий:
// "ОткрытьСуществующий", "ВзятьИзХранилищаИОткрыть", "Отменить".
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  ИмяФайлаСПутем - Строка - полное имя файла с путем в рабочем каталоге.
// 
//  ДанныеФайла    - Структура:
//                   Размер                       - Число.
//                   ДатаМодификацииУниверсальная - Дата.
//                   ВРабочемКаталогеНаЧтение     - Булево.
//
Процедура ДействиеПриОткрытииФайлаВРабочемКаталоге(ОбработчикРезультата, ИмяФайлаСПутем, ДанныеФайла)
	
	Если ДанныеФайла.Свойство("ПутьОбновленияИзФайлаНаДиске") Тогда
		ВернутьРезультат(ОбработчикРезультата, "ВзятьИзХранилищаИОткрыть");
		Возврат;
	КонецЕсли;
	
	Параметры = Новый Структура;
	Параметры.Вставить("ДействиеНадФайлом", "ОткрытиеВРабочемКаталоге");
	Параметры.Вставить("ПолноеИмяФайлаВРабочемКаталоге", ИмяФайлаСПутем);
	
	Файл = Новый Файл(Параметры.ПолноеИмяФайлаВРабочемКаталоге);
	
	Параметры.Вставить("ДатаИзмененияУниверсальнаяВХранилищеФайлов",
		ДанныеФайла.ДатаМодификацииУниверсальная);
	Параметры.Вставить("ДатаИзмененияУниверсальнаяВРабочемКаталоге",
		Файл.ПолучитьУниверсальноеВремяИзменения());
	Параметры.Вставить("ДатаИзмененияВРабочемКаталоге",
		МестноеВремя(Параметры.ДатаИзмененияУниверсальнаяВРабочемКаталоге));
	Параметры.Вставить("ДатаИзмененияВХранилищеФайлов",
		МестноеВремя(Параметры.ДатаИзмененияУниверсальнаяВХранилищеФайлов));
	Параметры.Вставить("РазмерВРабочемКаталоге", Файл.Размер());
	Параметры.Вставить("РазмерВХранилищеФайлов", ДанныеФайла.Размер);
	
	РазницаДат = Параметры.ДатаИзмененияУниверсальнаяВРабочемКаталоге
	           - Параметры.ДатаИзмененияУниверсальнаяВХранилищеФайлов;
	
	Если РазницаДат < 0 Тогда
		РазницаДат = -РазницаДат;
	КонецЕсли;
	
	Если РазницаДат <= 1 Тогда // С секунда - допустимая разница (на Win95 может быть такое).
		
		Если Параметры.РазмерВХранилищеФайлов <> 0
		   И Параметры.РазмерВХранилищеФайлов <> Параметры.РазмерВРабочемКаталоге Тогда
			// Дата одинаковая, но размер отличается - редкий, но возможный случай.
			
			Параметры.Вставить("Заголовок",
				НСтр("ru = 'Размер файла отличается'"));
			
			Параметры.Вставить("Сообщение",
				НСтр("ru = 'Размер файла в рабочем каталоге на компьютере и его копии в программе отличается.
				           |
				           |Взять файл из программы и заменить им существующий на компьютере или
				           |открыть существующий без обновления?'"));
		Иначе
			ВернутьРезультат(ОбработчикРезультата, "ОткрытьСуществующий");
			Возврат;
		КонецЕсли;
		
	ИначеЕсли Параметры.ДатаИзмененияУниверсальнаяВРабочемКаталоге
	        < Параметры.ДатаИзмененияУниверсальнаяВХранилищеФайлов Тогда
		// В хранилище файлов более новый файл.
		Если ДанныеФайла.ВРабочемКаталогеНаЧтение = Ложь Тогда
			Параметры.Вставить("Заголовок", НСтр("ru = 'В программе более новая версия файла'"));
			Параметры.Вставить("Сообщение",
				НСтр("ru = 'Файл в программе, отмеченный как занятый для редактирования,
				           |имеет более позднюю дату изменения (новее), чем его копия в рабочем каталоге на компьютере.
				           |
				           |Взять файл из программы и заменить им существующий на компьютере или
				           |открыть существующий?'"));
		Иначе
			ВернутьРезультат(ОбработчикРезультата, "ВзятьИзХранилищаИОткрыть");
			Возврат;
		КонецЕсли;
	
	ИначеЕсли Параметры.ДатаИзмененияУниверсальнаяВРабочемКаталоге
	        > Параметры.ДатаИзмененияУниверсальнаяВХранилищеФайлов Тогда
		// В рабочем каталоге более новый файл.
		
		Если ДанныеФайла.ВРабочемКаталогеНаЧтение = Ложь
		   И ДанныеФайла.Редактирует = ПользователиКлиент.АвторизованныйПользователь() Тогда
			
			// Файл в рабочем каталоге для редактирования и занят текущим пользователем.
			ВернутьРезультат(ОбработчикРезультата, "ОткрытьСуществующий");
			Возврат;
		Иначе
			// Файл в рабочем каталоге для чтения.
			Параметры.Вставить("Заголовок", НСтр("ru = 'На компьютере более новая копия файла'"));
			Параметры.Вставить(
				"Сообщение",
				НСтр("ru = 'Копия файла в рабочем каталоге на компьютере имеет более позднюю дату изменения (новее), чем в программе. Возможно, эта копия была отредактирована.
				           |
				           |Открыть существующий файл на компьютере или заменить его на файл
				           |из программы c потерей изменений и открыть?'"));
		КонецЕсли;
	КонецЕсли;
	
	ОткрытьФорму("ОбщаяФорма.ВыборДействияПриОбнаруженииОтличийФайла", Параметры, , , , , ОбработчикРезультата, РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);
	
КонецПроцедуры

// Возвращает каталог "Мои Документы".
//
Функция КаталогМоиДокументы()
	Возврат КаталогДокументов();
КонецФункции

// Возвращает путь к рабочему каталогу пользователя.
//
// Параметры:
//  Оповещение - ОписаниеОповещения - оповещение, которое выполняется после получения рабочего
//   каталога пользователя. В качестве результата возвращается Структура со свойствами:
//     * Каталог        - Строка - полное имя рабочего каталога пользователя.
//     * ОписаниеОшибки - Строка - текст ошибки, если каталог получить не удалось.
//
Процедура ПолучитьРабочийКаталогПользователя(Оповещение)
	
	ИмяПараметра = "СтандартныеПодсистемы.ПроверкаДоступаКРабочемуКаталогуВыполнена";
	Если ПараметрыПриложения[ИмяПараметра] = Неопределено Тогда
		ПараметрыПриложения.Вставить(ИмяПараметра, Ложь);
	КонецЕсли;
	
	ИмяКаталога =
		СтандартныеПодсистемыКлиент.ПараметрыРаботыКлиента().ПерсональныеНастройкиРаботыСФайлами.ПутьКЛокальномуКэшуФайлов;
	
	// Уже установлен.
	Если ИмяКаталога <> Неопределено
		И НЕ ПустаяСтрока(ИмяКаталога)
		И ПараметрыПриложения["СтандартныеПодсистемы.ПроверкаДоступаКРабочемуКаталогуВыполнена"] Тогда
		
		Результат = Новый Структура;
		Результат.Вставить("Каталог", ИмяКаталога);
		Результат.Вставить("ОписаниеОшибки", "");
		
		ВыполнитьОбработкуОповещения(Оповещение, Результат);
		Возврат;
	КонецЕсли;
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение", Оповещение);
	Контекст.Вставить("Каталог", ИмяКаталога);
	
	ПолучитьРабочийКаталогДанныхПользователя(Новый ОписаниеОповещения(
		"ПолучитьРабочийКаталогПользователяПослеПолученияКаталогаДанных", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры ПолучитьРабочийКаталогПользователя.
Процедура ПолучитьРабочийКаталогПользователяПослеПолученияКаталогаДанных(Результат, Контекст) Экспорт
	
	Если ЗначениеЗаполнено(Результат.ОписаниеОшибки) Тогда
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
		Возврат;
	КонецЕсли;
	
#Если НЕ ВебКлиент Тогда
	
	Если Результат.Каталог <> Контекст.Каталог Тогда
		// Создать каталог для файлов.
		Попытка
			СоздатьКаталог(Контекст.Каталог);
			ИмяКаталогаТестовое = Контекст.Каталог + "ПроверкаДоступа\";
			СоздатьКаталог(ИмяКаталогаТестовое);
			УдалитьФайлы(ИмяКаталогаТестовое);
		Исключение
			// Нет прав на создание каталога, или такой путь отсутствует,
			// тогда установка настроек по умолчанию.
			Контекст.Каталог = Неопределено;
			ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
				"Предупреждение", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()),, Истина);
		КонецПопытки;
	КонецЕсли;
	
#КонецЕсли
	
	ПараметрыПриложения["СтандартныеПодсистемы.ПроверкаДоступаКРабочемуКаталогуВыполнена"] = Истина;
	
	Если Контекст.Каталог = Неопределено Тогда
		УстановитьРабочийКаталогПользователя(Результат.Каталог);
	Иначе
		Результат.Каталог = Контекст.Каталог;
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
	
КонецПроцедуры

// Показывает напоминание о порядке работы с файлом в веб-клиенте,
// если включена настройка "Показывать подсказки при редактировании файлов".
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//
Процедура ВывестиНапоминаниеПриРедактировании(ОбработчикРезультата)
	ПерсональныеНастройки = ПерсональныеНастройкиРаботыСФайлами();
	Если ПерсональныеНастройки.ПоказыватьПодсказкиПриРедактированииФайлов = Истина Тогда
		Если НЕ РасширениеРаботыСФайламиПодключено() Тогда
			ТекстНапоминания = 
				НСтр("ru = 'Сейчас будет предложено открыть или сохранить файл.
				|
				|1. Нажмите кнопку ""Сохранить"" (""Save"").
				|
				|2. Выберите каталог для сохранения файла на компьютере и запомните его
				|(каталог понадобится для редактирования и помещения файла обратно в программу).
				|
				|3. Для редактирования файла перейдите в выбранный ранее каталог,
				|найдите там сохраненный файл и откройте его.'");
				
			СистемнаяИнформация = Новый СистемнаяИнформация;
			Если СтрНайти(СистемнаяИнформация.ИнформацияПрограммыПросмотра, "Firefox") <> 0 Тогда
				ТекстНапоминания = ТекстНапоминания
				+ "
				|
				|"
				+ НСтр("ru = '(По умолчанию браузер Mozilla Firefox автоматически сохраняет файлы в каталоге ""Мои документы"")'");
			КонецЕсли;
			Кнопки = Новый СписокЗначений;
			Кнопки.Добавить("Продолжить", НСтр("ru = 'Продолжить'"));
			Кнопки.Добавить("Отмена", НСтр("ru = 'Отмена'"));
			ПараметрыНапоминания = Новый Структура;
			ПараметрыНапоминания.Вставить("Картинка", БиблиотекаКартинок.Информация32);
			ПараметрыНапоминания.Вставить("ТекстФлажка",
				НСтр("ru = 'Больше не показывать это сообщение'"));
			ПараметрыНапоминания.Вставить("Заголовок",
				НСтр("ru = 'Получение файла для просмотра или редактирования'"));
			СтандартныеПодсистемыКлиент.ПоказатьВопросПользователю(
				ОбработчикРезультата, ТекстНапоминания, Кнопки, ПараметрыНапоминания);
			
			Возврат;
		КонецЕсли;
	КонецЕсли;
	ВернутьРезультат(ОбработчикРезультата, Истина);
КонецПроцедуры

// Продолжение процедуры ПроверитьПодписи.
Процедура ПроверитьПодписиПослеПодготовкиДанных(Данные, ДополнительныеПараметры)
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		Возврат;
	КонецЕсли;
	
	Если ДополнительныеПараметры.ВыделенныеСтроки = Неопределено Тогда
		Коллекция = ДополнительныеПараметры.Форма.ЭлектронныеПодписи;
	Иначе
		Коллекция = ДополнительныеПараметры.ВыделенныеСтроки;
	КонецЕсли;
	
	Если ОбщегоНазначенияКлиент.ПодсистемаСуществует("ТехнологияСервиса.ЭлектроннаяПодписьВМоделиСервиса") Тогда
		МодульЭлектроннаяПодписьВМоделиСервисаКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьВМоделиСервисаКлиент");
		ИспользоватьЭлектроннуюПодписьВМоделиСервиса = МодульЭлектроннаяПодписьВМоделиСервисаКлиент.ИспользованиеВозможно();
	Иначе
		ИспользоватьЭлектроннуюПодписьВМоделиСервиса = Ложь;
	КонецЕсли;
	
	ИспользоватьОблачнуюПодпись = Ложь;
	Если ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодписьСервисаDSS") Тогда
		МодульСервисКриптографииDSSКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("СервисКриптографииDSSКлиент");
		ИспользоватьОблачнуюПодпись = МодульСервисКриптографииDSSКлиент.ИспользоватьСервисОблачнойПодписи();
	КонецЕсли;
	
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	
	Если ИспользоватьЭлектроннуюПодписьВМоделиСервиса
	 Или ИспользоватьОблачнуюПодпись
	 Или Не МодульЭлектроннаяПодписьКлиент.ПроверятьЭлектронныеПодписиНаСервере() Тогда
		
		ДополнительныеПараметры.Вставить("Данные", Данные);
		ДополнительныеПараметры.Вставить("Коллекция", Коллекция);
		ДополнительныеПараметры.Вставить("МодульЭлектроннаяПодписьКлиент", МодульЭлектроннаяПодписьКлиент);
		ДополнительныеПараметры.Вставить("Индекс", -1);
		ПроверитьПодписиЦиклНачало(ДополнительныеПараметры);
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(Данные) = Тип("ДвоичныеДанные") Тогда
		АдресДанных = ПоместитьВоВременноеХранилище(Данные, ДополнительныеПараметры.ИдентификаторФормы);
	Иначе
		АдресДанных = Данные;
	КонецЕсли;
	
	ДанныеСтрок = Новый Массив;
	
	Для каждого Элемент Из Коллекция Цикл
		СтрокаПодписи = ?(ТипЗнч(Элемент) <> Тип("Число"), Элемент,
			ДополнительныеПараметры.Форма.ЭлектронныеПодписи.НайтиПоИдентификатору(Элемент));
		
		ДанныеСтроки = ДанныеСтрокиПодписи();
		ЗаполнитьЗначенияСвойств(ДанныеСтроки, СтрокаПодписи);
		ДанныеСтрок.Добавить(ДанныеСтроки);
		
	КонецЦикла;
	
	РаботаСФайламиСлужебныйВызовСервера.ПроверитьПодписи(АдресДанных, ДанныеСтрок, ДополнительныеПараметры.ПодписанныйОбъект);
	
	Индекс = 0;
	Для каждого Элемент Из Коллекция Цикл
		СтрокаПодписи = ?(ТипЗнч(Элемент) <> Тип("Число"), Элемент,
			ДополнительныеПараметры.Форма.ЭлектронныеПодписи.НайтиПоИдентификатору(Элемент));
		ЗаполнитьЗначенияСвойств(СтрокаПодписи, ДанныеСтрок[Индекс]);
		Индекс = Индекс + 1;
	КонецЦикла;
	
КонецПроцедуры

Функция ДанныеСтрокиПодписи()
	
	ДанныеСтроки = Новый Структура;
	ДанныеСтроки.Вставить("АдресПодписи");
	ДанныеСтроки.Вставить("Статус");
	ДанныеСтроки.Вставить("ПодписьВерна");
	ДанныеСтроки.Вставить("ДатаПодписи");
	ДанныеСтроки.Вставить("ОписаниеОшибки");
	ДанныеСтроки.Вставить("ДатаПроверкиПодписи");
	ДанныеСтроки.Вставить("ТипПодписи");
	ДанныеСтроки.Вставить("ТребуетсяПроверка");
	ДанныеСтроки.Вставить("СрокДействияПоследнейМеткиВремени");
	ДанныеСтроки.Вставить("РезультатПроверкиПодписиПоМЧД");
	Возврат ДанныеСтроки;
	
КонецФункции

// Помещает файлы с компьютера в хранилище присоединенных файлов.
//
// Параметры:
//  ВыбранныеФайлы                 - Массив из Строка - пути к файлам.
//  ВладелецФайла                  - ОпределяемыйТип.ВладелецФайлов - ссылка на владельца файла.
//  НастройкиРаботыСФайлами        - Структура.
//  ПрисоединенныеФайлыМассив      - Массив из ОпределяемыйТип.ПрисоединенныйФайл - возвращаемое значение. заполняется ссылками
//                                   на добавленные файлы.
//  ИдентификаторФормы             - УникальныйИдентификатор - УникальныйИдентификатор формы.
//
Процедура ПоместитьВыбранныеФайлыВХранилище(Знач ВыбранныеФайлы,
                                            Знач ВладелецФайла,
                                            ПрисоединенныеФайлыМассив,
                                            Знач ИдентификаторФормы,
                                            Знач ИмяСоздаваемогоФайла = "",
                                            Знач ГруппаФайлов = Неопределено)
	
	ОбщиеНастройки = ОбщиеНастройкиРаботыСФайлами();
	
	ТекущаяПозиция = 0;
	
	ПоследнийСохраненныйФайл = Неопределено;
	
	Для Каждого ПолноеИмяФайла Из ВыбранныеФайлы Цикл
		
		ТекущаяПозиция = ТекущаяПозиция + 1;		
		Файл = Новый Файл(ПолноеИмяФайла);		
		ПроверитьВозможностьЗагрузкиФайла(Файл);
		
		Если ОбщиеНастройки.ИзвлекатьТекстыФайловНаСервере Тогда
			АдресВременногоХранилищаТекста = "";
		Иначе
			АдресВременногоХранилищаТекста = ИзвлечьТекстВоВременноеХранилище(ПолноеИмяФайла, ИдентификаторФормы);
		КонецЕсли;
	
		ВремяИзмененияУниверсальное = Файл.ПолучитьУниверсальноеВремяИзменения();
		
		ОбновитьСостояниеОСохраненииФайлов(ВыбранныеФайлы, Файл, ТекущаяПозиция, ИмяСоздаваемогоФайла);
		ПоследнийСохраненныйФайл = Файл;
		
		ПомещаемыеФайлы = Новый Массив;
		Описание = Новый ОписаниеПередаваемогоФайла(Файл.ПолноеИмя, "");
		ПомещаемыеФайлы.Добавить(Описание);
		
		ПомещенныеФайлы = Новый Массив;		
		Если НЕ ПоместитьФайлы(ПомещаемыеФайлы, ПомещенныеФайлы, , Ложь, ИдентификаторФормы) Тогда
			ОбщегоНазначенияКлиент.СообщитьПользователю(
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось поместить в программу файл ""%1"".'"),
					Файл.ПолноеИмя) );
			Продолжить;
		КонецЕсли;
		
		АдресВременногоХранилищаФайла = ПомещенныеФайлы[0].Хранение;
		
	#Если МобильныйКлиент Тогда
		ПредставлениеНаМобильномУстройстве = Файл.ПолучитьПредставлениеФайлаБиблиотекиМобильногоУстройства();
		РасширениеФайла = ОбщегоНазначенияКлиентСервер.ПолучитьРасширениеИмениФайла(ПредставлениеНаМобильномУстройстве);
		ИмяФайлаБезРасширения = СтрЗаменить(ПредставлениеНаМобильномУстройстве, "." + РасширениеФайла, "");
	#Иначе
		РасширениеФайла = ОбщегоНазначенияКлиентСервер.РасширениеБезТочки(Файл.Расширение);
		ИмяФайлаБезРасширения = Файл.ИмяБезРасширения;
	#КонецЕсли
	
		ИмяБезРасширения = ?(ПустаяСтрока(ИмяСоздаваемогоФайла), ИмяФайлаБезРасширения, ИмяСоздаваемогоФайла);
		
		ПараметрыФайла = РаботаСФайламиСлужебныйКлиентСервер.ПараметрыДобавленияФайла();
		ПараметрыФайла.ГруппаФайлов = ГруппаФайлов;
		ПараметрыФайла.ВладелецФайлов = ВладелецФайла;
		ПараметрыФайла.ИмяБезРасширения = ИмяБезРасширения;
		ПараметрыФайла.РасширениеБезТочки = РасширениеФайла;
		ПараметрыФайла.ВремяИзмененияУниверсальное = ВремяИзмененияУниверсальное;
		
		ПрисоединенныйФайл = РаботаСФайламиСлужебныйВызовСервера.ДобавитьФайл(ПараметрыФайла,
			АдресВременногоХранилищаФайла, АдресВременногоХранилищаТекста);		
		Если ПрисоединенныйФайл = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		ПрисоединенныеФайлыМассив.Добавить(ПрисоединенныйФайл);
		
	КонецЦикла;
	
	ОбновитьСостояниеОСохраненииФайлов(ВыбранныеФайлы, ПоследнийСохраненныйФайл, , ИмяБезРасширения);
	
КонецПроцедуры

Процедура ОбновитьСостояниеОСохраненииФайлов(Знач ВыбранныеФайлы,
											 Знач Файл,
											 Знач ТекущаяПозиция = Неопределено,
											 ИмяСоздаваемогоФайла = "");
	
	Если Файл = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	СохраняемоеИмяФайла = ?(ПустаяСтрока(ИмяСоздаваемогоФайла), Файл.Имя, ИмяСоздаваемогоФайла);
	
	РазмерВМб = РаботаСФайламиСлужебныйКлиентСервер.ПолучитьСтрокуСРазмеромФайла(Файл.Размер() / (1024 * 1024));
	
	Если ВыбранныеФайлы.Количество() > 1 Тогда
		Если ТекущаяПозиция = Неопределено Тогда
			ПоказатьОповещениеПользователя(НСтр("ru = 'Сохранение файлов'"),, НСтр("ru = 'Сохранение файлов успешно завершено'"));
		КонецЕсли;
	Иначе
		Если ТекущаяПозиция = Неопределено Тогда
			ТекстПояснения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Файл ""%1"" (%2 Мб) сохранен.'"),
				СохраняемоеИмяФайла,
				РазмерВМб);
			ПоказатьОповещениеПользователя(НСтр("ru = 'Сохранение файла'"), , ТекстПояснения, БиблиотекаКартинок.Информация32);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Помещает файл с компьютера в хранилище присоединенных файлов (веб-клиент).
// 
// Параметры:
//  ОбработчикРезультата    - ОписаниеОповещения - процедура, в которую необходимо передать управление при завершении.
//                            Параметры вызываемой процедуры:
//                             ПрисоединенныйФайл      - ЛюбаяСсылка, Неопределено - ссылка на добавленный файл, либо
//                                                       Неопределено, если файл не был помещен;
//                             ДополнительныеПараметры - Произвольный - значение, которое было указано при создании
//                                                                      объекта оповещения.
//  ВладелецФайла           - ссылка на владельца файла.
//  НастройкиРаботыСФайлами - Структура.
//  ИдентификаторФормы      - УникальныйИдентификатор формы.
//
Процедура ПоместитьВыбранныеФайлыВХранилищеВеб(ОбработчикРезультата, Знач ВладелецФайла, Знач ИдентификаторФормы)
	
	Параметры = Новый Структура;
	Параметры.Вставить("ВладелецФайла", ВладелецФайла);
	Параметры.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	
	ОписаниеОповещения = Новый ОписаниеОповещения("ПоместитьВыбранныеФайлыВХранилищеВебЗавершение", ЭтотОбъект, Параметры);
	НачатьПомещениеФайла(ОписаниеОповещения, , ,Истина, ИдентификаторФормы);
	
КонецПроцедуры

// Продолжение процедуры ПоместитьВыбранныеФайлыВХранилищеВеб.
Процедура ПоместитьВыбранныеФайлыВХранилищеВебЗавершение(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
	
	Обработчик = ДополнительныеПараметры.ОбработчикРезультата; // ОписаниеОповещения
	Если Не Результат Тогда
		ВыполнитьОбработкуОповещения(Обработчик, Неопределено);
		Возврат;
	КонецЕсли;
	
	ВладелецФайла = ДополнительныеПараметры.ВладелецФайла;
	СтруктураПути = ОбщегоНазначенияКлиентСервер.РазложитьПолноеИмяФайла(ВыбранноеИмяФайла);
	ГруппаФайлов = ?(Обработчик.ДополнительныеПараметры.Свойство("ГруппаФайлов"),
		Обработчик.ДополнительныеПараметры.ГруппаФайлов, "");
	
	Если Не ПустаяСтрока(СтруктураПути.Расширение) Тогда
		Расширение = ОбщегоНазначенияКлиентСервер.РасширениеБезТочки(СтруктураПути.Расширение);
		ИмяБезРасширения = СтруктураПути.ИмяБезРасширения;
	Иначе
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось поместить в программу файл ""%1"".'"),
			ВыбранноеИмяФайла);
	КонецЕсли;
	
	ПроверитьРасширениеФайлаДляЗагрузки(Расширение);
	
	ОбщиеНастройки = ОбщиеНастройкиРаботыСФайлами();
	РазмерЗагружаемогоФайла = ПолучитьИзВременногоХранилища(Адрес).Размер();
	Если РазмерЗагружаемогоФайла > ОбщиеНастройки.МаксимальныйРазмерФайла Тогда
		
		РазмерВМб     = РазмерЗагружаемогоФайла / (1024 * 1024);
		РазмерВМбМакс = ОбщиеНастройки.МаксимальныйРазмерФайла / (1024 * 1024);
		
		ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Размер файла ""%1"" (%2 Мб)
			|превышает максимально допустимый размер файла (%3 Мб).'"),
			ВыбранноеИмяФайла,
			РаботаСФайламиСлужебныйКлиентСервер.ПолучитьСтрокуСРазмеромФайла(РазмерВМб),
			РаботаСФайламиСлужебныйКлиентСервер.ПолучитьСтрокуСРазмеромФайла(РазмерВМбМакс));
		
		ВызватьИсключение ОписаниеОшибки;
		
	КонецЕсли;
	
	ПараметрыФайла = РаботаСФайламиСлужебныйКлиентСервер.ПараметрыДобавленияФайла();
	ПараметрыФайла.ВладелецФайлов = ВладелецФайла;
	ПараметрыФайла.ИмяБезРасширения = ИмяБезРасширения;
	ПараметрыФайла.РасширениеБезТочки = Расширение;
	Если ЗначениеЗаполнено(ГруппаФайлов) Тогда
		ПараметрыФайла.ГруппаФайлов = ГруппаФайлов;
	КонецЕсли;
	
	// Создание карточки Файла в базе данных.
	ПрисоединенныйФайл = РаботаСФайламиСлужебныйВызовСервера.ДобавитьФайл(
		ПараметрыФайла, Адрес);
		
	ВыполнитьОбработкуОповещения(Обработчик, ПрисоединенныйФайл);
	
КонецПроцедуры

// Проверяет можно ли освободить Файл.
//
// Параметры:
//  ОбъектСсылка - СправочникСсылка.Файлы - файл.
//
//  РедактируетТекущийПользователь - Булево -
//                 файл редактирует текущий пользователь.
//
//  Редактирует  - СправочникСсылка.Пользователи - тот, кто занял файл.
//
//  СтрокаОшибки - Строка - в которой возвращается причина ошибки в случае неуспеха
//                 (например, "Файл занят другим пользователем").
//
// Возвращаемое значение:
//  Булево -  Истина, если файл можно освободить.
//
Функция ВозможностьОсвободитьФайл(ОбъектСсылка,
                                  РедактируетТекущийПользователь,
                                  Редактирует,
                                  СтрокаОшибки = "") Экспорт
	
	Если РедактируетТекущийПользователь Тогда 
		Возврат Истина;
	ИначеЕсли Не ЗначениеЗаполнено(Редактирует) Тогда
		СтрокаОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Невозможно освободить файл ""%1"",
			           |т.к. он никем не занят.'"),
			Строка(ОбъектСсылка));
		Возврат Ложь;
	Иначе
		Если ПользователиКлиент.ЭтоПолноправныйПользователь() Тогда
			Возврат Истина;
		КонецЕсли;
		
		СтрокаОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Невозможно освободить файл ""%1"",
			           |т.к. он занят пользователем ""%2"".'"),
			Строка(ОбъектСсылка),
			Строка(Редактирует));
		Возврат Ложь;
	КонецЕсли;
	
КонецФункции

Процедура ОсвободитьФайлы(СписокФайлов) Экспорт
	МассивФайлов = Новый Массив;
	Для Каждого ЭлементСписка Из СписокФайлов.ВыделенныеСтроки Цикл
		ДанныеСтроки = СписокФайлов.ДанныеСтроки(ЭлементСписка); // ОпределяемыйТип.ПрисоединенныйФайл
		Если Не ВозможностьОсвободитьФайл(
				ДанныеСтроки.Ссылка,
				ДанныеСтроки.ФайлРедактируетТекущийПользователь,
				ДанныеСтроки.Редактирует) Тогда
			Продолжить;
		КонецЕсли;
		МассивФайлов.Добавить(ДанныеСтроки.Ссылка);
	КонецЦикла;
	
	Если МассивФайлов.Количество() = 0 Тогда 
		Возврат;
	КонецЕсли;
	
	ДанныеФайлов = РаботаСФайламиСлужебныйВызовСервера.ОсвободитьФайлы(МассивФайлов);
	
	// Удаляем файлы из рабочего каталога, чтобы не подхватить измененные файлы при новом редактировании.
	Обработчик = Новый ОписаниеОповещения;
	Для Каждого Файл Из МассивФайлов Цикл
		ВерсияФайла = ДанныеФайлов.ВерсииФайлов.Получить(Файл);
		УдалитьФайлИзРабочегоКаталога(Обработчик, ВерсияФайла, Истина);
	КонецЦикла;
	
	СтандартныеПодсистемыКлиент.УстановитьПараметрКлиента("КоличествоЗанятыхФайлов", 
		ДанныеФайлов.КоличествоЗанятыхФайлов);
	Если МассивФайлов.Количество() > 1 Тогда
		ОповеститьОбИзменении(ТипЗнч(МассивФайлов[0]));
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла(), Неопределено);
	Иначе	
		ОповеститьОбИзменении(МассивФайлов[0]);
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла(), МассивФайлов[0]);
	КонецЕсли;

КонецПроцедуры

// Освобождает файл без обновления.
//
// Параметры:
//  ДанныеФайла             - Структура
//  УникальныйИдентификатор - УникальныйИдентификатор управляемой формы.
//
Процедура ОсвободитьФайлБезВопроса(ДанныеФайла, УникальныйИдентификатор = Неопределено)
	
	РаботаСФайламиСлужебныйВызовСервера.ОсвободитьФайл(ДанныеФайла, УникальныйИдентификатор);
	ИзменитьКоличествоЗанятыхФайлов();
	
	РасширениеПодключено = РасширениеРаботыСФайламиПодключено();
	Если РасширениеПодключено Тогда
		ПеререгистрироватьФайлВРабочемКаталоге(ДанныеФайла, Истина, ДанныеФайла.РабочийКаталогВладельца <> "");
	КонецЕсли;
	
	ПоказатьОповещениеПользователя(НСтр("ru = 'Файл освобожден'"),
		ДанныеФайла.НавигационнаяСсылка, ДанныеФайла.ПолноеНаименованиеВерсии, БиблиотекаКартинок.Информация32);
	
КонецПроцедуры

// Перемещает файлы в указанную папку.
//
// Параметры:
//  ОбъектыСсылка - Массив - массив файлов.
//
//  Папка         - СправочникСсылка.ПапкиФайлов - папка,
//                  в которую требуется перенести файлы.
//
Процедура ПеренестиФайлыВПапку(ОбъектыСсылка, Папка) Экспорт
	
	ДанныеФайлов = РаботаСФайламиСлужебныйВызовСервера.ПеренестиФайлы(ОбъектыСсылка, Папка);
	
	Для Каждого ДанныеФайла Из ДанныеФайлов Цикл
		
		ПоказатьОповещениеПользователя(
			НСтр("ru = 'Перенос файла'"),
			ДанныеФайла.НавигационнаяСсылка,
			СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Файл ""%1""
				           |перенесен в папку ""%2"".'"),
				Строка(ДанныеФайла.Ссылка),
				Строка(Папка)),
			БиблиотекаКартинок.Информация32);
		
	КонецЦикла;
	
КонецПроцедуры

// Извлечь текст из файла и поместить во временное хранилище.
Функция ИзвлечьТекстВоВременноеХранилище(ПолноеИмяФайла, УникальныйИдентификатор = "", Отказ = Ложь,
	Кодировка = Неопределено)
	
	АдресВременногоХранилища = "";
	
	#Если Не ВебКлиент Тогда
		
		Текст = ИзвлечьТекст(ПолноеИмяФайла, Отказ, Кодировка);
		
		Если ПустаяСтрока(Текст) Тогда
			Возврат "";
		КонецЕсли;
		
		ИмяВременногоФайла = ПолучитьИмяВременногоФайла();
		ТекстовыйФайл = Новый ЗаписьТекста(ИмяВременногоФайла, КодировкаТекста.UTF8);
		ТекстовыйФайл.Записать(Текст);
		ТекстовыйФайл.Закрыть();
		
		РезультатЗагрузки = ПоместитьФайлСДискаВоВременноеХранилище(ИмяВременногоФайла, , УникальныйИдентификатор);
		Если РезультатЗагрузки <> Неопределено Тогда
			АдресВременногоХранилища = РезультатЗагрузки;
		КонецЕсли;
	
		Попытка	
			УдалитьФайлы(ИмяВременногоФайла);
		Исключение
			ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
				"Предупреждение", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()),, Истина);
		КонецПопытки;	
		
	#КонецЕсли
	
	Возврат АдресВременногоХранилища;
	
КонецФункции

// Возвращает строковую константу для формирования сообщений журнала регистрации.
//
// Возвращаемое значение:
//   Строка
//
Функция СобытиеЖурналаРегистрации()
	
	Возврат НСтр("ru = 'Файлы'", ОбщегоНазначенияКлиент.КодОсновногоЯзыка());
	
КонецФункции

// Возвращает текст сообщения об ошибке создания нового файла.
//
// Параметры:
//  ИнформацияОбОшибке - ИнформацияОбОшибке.
//
Функция ОшибкаСозданияНовогоФайла(ИнформацияОбОшибке)
	
	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Не удалось создать файл по причине:
		           |%1'"),
		ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));

КонецФункции

// Проверяет расширение файла и размер.
//
// Параметры:
//   Файл - Файл
//   ВызыватьИсключение - Булево
//   ФайлыСОшибками - Массив из Структура:
//     * ИмяФайла - Строка
//     * Ошибка - Строка
//
Функция ПроверитьВозможностьЗагрузкиФайла(Файл, ВызыватьИсключение = Истина, ФайлыСОшибками = Неопределено)
	
	ОбщиеНастройки = ОбщиеНастройкиРаботыСФайлами();
	
	// Размер файла слишком большой.
	Если Файл.Размер() > ОбщиеНастройки.МаксимальныйРазмерФайла Тогда
		
		РазмерВМб     = Файл.Размер() / (1024 * 1024);
		РазмерВМбМакс = ОбщиеНастройки.МаксимальныйРазмерФайла / (1024 * 1024);
		
		ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Размер файла ""%1"" (%2 Мб)
			           |превышает максимально допустимый размер файла (%3 Мб).'"),
			Файл.Имя,
			РаботаСФайламиСлужебныйКлиентСервер.ПолучитьСтрокуСРазмеромФайла(РазмерВМб),
			РаботаСФайламиСлужебныйКлиентСервер.ПолучитьСтрокуСРазмеромФайла(РазмерВМбМакс));
		
		Если ВызыватьИсключение Тогда
			ВызватьИсключение ОписаниеОшибки;
		КонецЕсли;
		
		Запись = Новый Структура;
		Запись.Вставить("ИмяФайла", Файл.ПолноеИмя);
		Запись.Вставить("Ошибка",   ОписаниеОшибки);
		
		ФайлыСОшибками.Добавить(Запись);
		Возврат Ложь;
	КонецЕсли;
	
	// Проверка расширения файла.
	Если Не ПроверитьРасширениеФайлаДляЗагрузки(Файл.Расширение, Ложь) Тогда
		
		ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Загрузка файлов с расширением ""%1"" запрещена.
			           |Обратитесь к администратору.'"),
			Файл.Расширение);
		
		Если ВызыватьИсключение Тогда
			ВызватьИсключение ОписаниеОшибки;
		КонецЕсли;
		
		Запись = Новый Структура;
		Запись.Вставить("ИмяФайла", Файл.ПолноеИмя);
		Запись.Вставить("Ошибка",   ОписаниеОшибки);
		
		ФайлыСОшибками.Добавить(Запись);
		Возврат Ложь;
	КонецЕсли;
	
	// Временные файлы Word не импортируются.
	Если СтрНачинаетсяС(Файл.Имя, "~")
		И Файл.ПолучитьНевидимость() Тогда
		
		Возврат Ложь;
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Завершение редактирования Файла и помещение его на сервер.

// Завершить редактирования Файла и поместить его на сервер.
//
// Параметры:
//   Параметры - см. ПараметрыОбновленияФайла.
//
Процедура ЗакончитьРедактирование(Параметры)
	
	Обработчик = Новый ОписаниеОповещения("ЗакончитьРедактированиеПослеУстановкиРасширения", ЭтотОбъект, Параметры);
	ПоказатьВопросОбУстановкеРасширенияРаботыСФайлами(Обработчик);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеПослеУстановкиРасширения(РасширениеУстановлено, ПараметрыВыполнения) Экспорт
	ПараметрыВыполнения.Вставить("ДанныеФайла", Неопределено);
	
	Если РасширениеРаботыСФайламиПодключено() Тогда
		ЗакончитьРедактированиеСРасширением(ПараметрыВыполнения);
	Иначе
		ЗакончитьРедактированиеБезРасширения(ПараметрыВыполнения);
	КонецЕсли;
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеСРасширением(ПараметрыВыполнения)
	// Веб-клиент с расширением для работы с файлами,
	// Тонкий клиент,
	// Толстый клиент.
	
	ДанныеФайла = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИРабочийКаталог(ПараметрыВыполнения.ОбъектСсылка);
	ПараметрыВыполнения.ДанныеФайла = ДанныеФайла;
	
	// Проверка возможности освобождения файла.
	ТекстОшибки = "";
	МожноОсвободитьФайл = ВозможностьОсвободитьФайл(
		ДанныеФайла.Ссылка,
		ДанныеФайла.ФайлРедактируетТекущийПользователь,
		ДанныеФайла.Редактирует,
		ТекстОшибки);
	Если Не МожноОсвободитьФайл Тогда
		ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, ТекстОшибки, Ложь);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.Вставить("ПолныйПутьКФайлу", ПараметрыВыполнения.ПереданныйПолныйПутьКФайлу);
	Если ПараметрыВыполнения.ПолныйПутьКФайлу = "" Тогда
		ПараметрыВыполнения.ПолныйПутьКФайлу = ДанныеФайла.ПолноеИмяФайлаВРабочемКаталоге;
	КонецЕсли;
	
	// Проверка наличия файла.
	ПараметрыВыполнения.Вставить("ФайлНовойВерсии", Новый Файл(ПараметрыВыполнения.ПолныйПутьКФайлу));
	
	Если Не ЗначениеЗаполнено(ПараметрыВыполнения.ПолныйПутьКФайлу)
	 Или Не ПараметрыВыполнения.ФайлНовойВерсии.Существует() Тогда
		
		Если ПараметрыВыполнения.ПрименитьКоВсем = Ложь Тогда
			Если Не ПустаяСтрока(ПараметрыВыполнения.ПолныйПутьКФайлу) Тогда
				СтрокаПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось поместить файл
					           |""%1"" (%2)
					           |в программу, т.к. он не существует в рабочем каталоге на компьютере.
					           |
					           |Освободить файл?'"),
					Строка(ДанныеФайла.Ссылка),
					ПараметрыВыполнения.ПолныйПутьКФайлу);
			Иначе
				СтрокаПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось поместить файл ""%1""
					           |в программу, т.к. он не существует в рабочем каталоге на компьютере.
					           |
					           |Освободить файл?'"),
					Строка(ДанныеФайла.Ссылка));
			КонецЕсли;
			
			Обработчик = Новый ОписаниеОповещения("ЗакончитьРедактированиеСРасширениемПослеОтветаНаВопросОсвободитьФайл", ЭтотОбъект, ПараметрыВыполнения);
			ПоказатьВопрос(Обработчик, СтрокаПредупреждения, РежимДиалогаВопрос.ДаНет);
		Иначе
			ЗакончитьРедактированиеСРасширениемПослеОтветаНаВопросОсвободитьФайл(-1, ПараметрыВыполнения)
		КонецЕсли;
		
		Возврат;
	КонецЕсли;
	
	Попытка
		ТолькоЧтение = ПараметрыВыполнения.ФайлНовойВерсии.ПолучитьТолькоЧтение();
		ПараметрыВыполнения.ФайлНовойВерсии.УстановитьТолькоЧтение(Не ТолькоЧтение);
		ПараметрыВыполнения.ФайлНовойВерсии.УстановитьТолькоЧтение(ТолькоЧтение);
	Исключение
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось поместить файл ""%1"" в рабочий каталог на компьютер,
				|так как возможно он заблокирован другой программой.'"),
			Строка(ДанныеФайла.Ссылка));
		ВызватьИсключение ТекстОшибки + Символы.ПС + Символы.ПС + ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
	КонецПопытки;
	
	// Запрос комментария и признака хранения версии.
	Если ПараметрыВыполнения.СоздатьНовуюВерсию = Неопределено Тогда
		
		ПараметрыВыполнения.СоздатьНовуюВерсию = ДанныеФайла.ХранитьВерсии;
		Если ДанныеФайла.ХранитьВерсии Тогда
			// Если автор текущей версии не текущий пользователь, тогда
			// отключается доступность флажка "Не создавать новую версию".
			СоздатьНовуюВерсиюДоступность = ДанныеФайла.АвторТекущейВерсии = ДанныеФайла.Редактирует;
			
			ВозвратФайла = Новый Структура;
			ВозвратФайла.Вставить("ФайлСсылка", ДанныеФайла.Ссылка);
			ВозвратФайла.Вставить("КомментарийКВерсии", "");
			ВозвратФайла.Вставить("СоздатьНовуюВерсию", ПараметрыВыполнения.СоздатьНовуюВерсию);
			ВозвратФайла.Вставить("СоздатьНовуюВерсиюДоступность", СоздатьНовуюВерсиюДоступность);
			
			Обработчик = Новый ОписаниеОповещения("ЗакончитьРедактированиеСРасширениемПослеПомещенияФайлаНаСервер", ЭтотОбъект, ПараметрыВыполнения);
			ОткрытьФорму("Обработка.РаботаСФайлами.Форма.ФормаВозвратаФайла", ВозвратФайла, , , , , Обработчик);
			
		Иначе
			ЗакончитьРедактированиеСРасширениемПослеПроверкиНовойВерсии(ПараметрыВыполнения);
		КонецЕсли;
		
	Иначе // Параметры СоздатьНовуюВерсию и КомментарийКВерсии переданы извне.
		
		Если ДанныеФайла.ХранитьВерсии Тогда
			
			// Если автор текущей версии не текущий пользователь, тогда
			// отключается доступность флажка "Не создавать новую версию".
			Если ДанныеФайла.АвторТекущейВерсии <> ДанныеФайла.Редактирует Тогда
				ПараметрыВыполнения.СоздатьНовуюВерсию = Истина;
			КонецЕсли;
			
		Иначе
			ПараметрыВыполнения.СоздатьНовуюВерсию = Ложь;
		КонецЕсли;
		
		ЗакончитьРедактированиеСРасширениемПослеПроверкиНовойВерсии(ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеСРасширениемПослеОтветаНаВопросОсвободитьФайл(Ответ, ПараметрыВыполнения) Экспорт
	Если Ответ <> -1 Тогда
		Если Ответ = КодВозвратаДиалога.Да Тогда
			ПараметрыВыполнения.ОсвобождатьФайлы = Истина;
		Иначе
			ПараметрыВыполнения.ОсвобождатьФайлы = Ложь;
		КонецЕсли;
	КонецЕсли;
	
	Если ПараметрыВыполнения.ОсвобождатьФайлы Тогда
		ОсвободитьФайлБезВопроса(ПараметрыВыполнения.ДанныеФайла, ПараметрыВыполнения.ИдентификаторФормы);
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Истина);
	Иначе
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
	КонецЕсли;
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеСРасширениемПослеПомещенияФайлаНаСервер(Результат, ПараметрыВыполнения) Экспорт
	
	Если ТипЗнч(Результат) <> Тип("Структура") Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	Если Результат.КодВозврата <> КодВозвратаДиалога.ОК Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.СоздатьНовуюВерсию = Результат.СоздатьНовуюВерсию;
	ПараметрыВыполнения.КомментарийКВерсии = Результат.КомментарийКВерсии;
	
	ЗакончитьРедактированиеСРасширениемПослеПроверкиНовойВерсии(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеСРасширениемПослеПроверкиНовойВерсии(ПараметрыВыполнения)
	
	Если Не ПараметрыВыполнения.ДанныеФайла.Зашифрован Тогда
		ЗакончитьРедактированиеСРасширениемПослеПроверкиЗашифрован(ПараметрыВыполнения);
		Возврат;
	КонецЕсли;
	
	// Файл с признаком шифрован снова шифруется для тех же сертификатов.
	
	ЗашифроватьФайлПередПомещениемВХранилищеФайлов(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеСРасширениемПослеПроверкиЗашифрован(ПараметрыВыполнения)
	
	СведенияОФайле = РаботаСФайламиКлиентСервер.СведенияОФайле("ФайлСВерсией", ПараметрыВыполнения.ФайлНовойВерсии);
	СведенияОФайле.Комментарий = ПараметрыВыполнения.КомментарийКВерсии;
	СведенияОФайле.ХранитьВерсии = ПараметрыВыполнения.СоздатьНовуюВерсию;
	
	Если ПараметрыВыполнения.Свойство("АдресПослеШифрования") Тогда
		СведенияОФайле.АдресВременногоХранилищаФайла = ПараметрыВыполнения.АдресПослеШифрования;
	Иначе
		ПомещаемыеФайлы = Новый Массив;
		Описание = Новый ОписаниеПередаваемогоФайла(ПараметрыВыполнения.ПолныйПутьКФайлу, "");
		ПомещаемыеФайлы.Добавить(Описание);
		
		ПомещенныеФайлы = Новый Массив;
		Попытка
			ФайлыПомещены = ПоместитьФайлы(ПомещаемыеФайлы, ПомещенныеФайлы,, Ложь, ПараметрыВыполнения.ИдентификаторФормы);
		Исключение
			ИнформацияОбОшибке = ИнформацияОбОшибке();
			
			ТекстВопроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось поместить файл с компьютера в программу по причине:
				|""%1"".
				|
				|Повторить операцию?'"),
				ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
			
			Оповещение  = Новый ОписаниеОповещения("ЗакончитьРедактированиеСРасширениемПослеПроверкиЗашифрованПовтор", ЭтотОбъект, ПараметрыВыполнения);
			ПоказатьВопрос(Оповещение, ТекстВопроса, РежимДиалогаВопрос.ПовторитьОтмена);
			Возврат;
		КонецПопытки;
		
		Если Не ФайлыПомещены Тогда
			ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
			Возврат;
		КонецЕсли;
		
		Если ПомещенныеФайлы.Количество() = 1 Тогда
			СведенияОФайле.АдресВременногоХранилищаФайла = ПомещенныеФайлы[0].Хранение;
		КонецЕсли;
	КонецЕсли;
	
	ОбщиеНастройкиРаботыСФайлами = ОбщиеНастройкиРаботыСФайлами();
	Если Не ОбщиеНастройкиРаботыСФайлами.ИзвлекатьТекстыФайловНаСервере Тогда
		Попытка
			СведенияОФайле.АдресВременногоХранилищаТекста = ИзвлечьТекстВоВременноеХранилище(ПараметрыВыполнения.ПолныйПутьКФайлу,
				ПараметрыВыполнения.ИдентификаторФормы,, ПараметрыВыполнения.Кодировка);
		Исключение
			ЗакончитьРедактированиеСРасширениемОбработкаИсключения(ИнформацияОбОшибке(), ПараметрыВыполнения);
			Возврат;
		КонецПопытки;
	КонецЕсли;
	
	НеМенятьЗаписьВРабочемКаталоге = Ложь;
	Если ПараметрыВыполнения.ПереданныйПолныйПутьКФайлу <> "" Тогда
		НеМенятьЗаписьВРабочемКаталоге = Истина;
	КонецЕсли;
	
	Попытка
		ВерсияОбновлена = РаботаСФайламиСлужебныйВызовСервера.СохранитьИзмененияИОсвободитьФайл(ПараметрыВыполнения.ДанныеФайла, СведенияОФайле, 
			НеМенятьЗаписьВРабочемКаталоге, ПараметрыВыполнения.ПолныйПутьКФайлу, РабочийКаталогПользователя(), 
			ПараметрыВыполнения.ИдентификаторФормы);
	Исключение
		ЗакончитьРедактированиеСРасширениемОбработкаИсключения(ИнформацияОбОшибке(), ПараметрыВыполнения);
		Возврат;
	КонецПопытки;
	
	ИзменитьКоличествоЗанятыхФайлов();
	
	ПараметрыВыполнения.Вставить("ВерсияОбновлена", ВерсияОбновлена);
	НоваяВерсия = ПараметрыВыполнения.ДанныеФайла.ТекущаяВерсия;
	
	Если ПараметрыВыполнения.ПереданныйПолныйПутьКФайлу = "" Тогда
		
		ПерсональныеНастройкиРаботыСФайлами = ПерсональныеНастройкиРаботыСФайлами();
		УдалятьФайлИзЛокальногоКэшаФайловПриЗавершенииРедактирования = ПерсональныеНастройкиРаботыСФайлами.УдалятьФайлИзЛокальногоКэшаФайловПриЗавершенииРедактирования;
		Если ПараметрыВыполнения.ДанныеФайла.РабочийКаталогВладельца <> "" Тогда
			УдалятьФайлИзЛокальногоКэшаФайловПриЗавершенииРедактирования = Ложь;
		КонецЕсли;
		
		Если УдалятьФайлИзЛокальногоКэшаФайловПриЗавершенииРедактирования Тогда
			Обработчик = Новый ОписаниеОповещения("ЗакончитьРедактированиеСРасширениемПослеУдаленияФайлаИзРабочегоКаталога", ЭтотОбъект, ПараметрыВыполнения);
			УдалитьФайлИзРабочегоКаталога(Обработчик, НоваяВерсия, УдалятьФайлИзЛокальногоКэшаФайловПриЗавершенииРедактирования);
			Возврат;
		Иначе
			Файл = Новый Файл(ПараметрыВыполнения.ПолныйПутьКФайлу);
			Файл.УстановитьТолькоЧтение(Истина);
		КонецЕсли;
	КонецЕсли;
	
	ЗакончитьРедактированиеСРасширениемПослеУдаленияФайлаИзРабочегоКаталога(-1, ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
Процедура ЗакончитьРедактированиеСРасширениемПослеПроверкиЗашифрованПовтор(Результат, Параметр) Экспорт
	Если Результат = КодВозвратаДиалога.Повторить Тогда
		ЗакончитьРедактированиеСРасширениемПослеПроверкиЗашифрован(Параметр);
	КонецЕсли;
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИРабочийКаталог
//
Процедура ЗакончитьРедактированиеСРасширениемПослеУдаленияФайлаИзРабочегоКаталога(Результат, ПараметрыВыполнения) Экспорт
	
	Если ПараметрыВыполнения.ПоказыватьОповещение Тогда
		Если ПараметрыВыполнения.ВерсияОбновлена Тогда
			ШаблонПояснения = НСтр("ru = 'Файл ""%1""
			                             |обновлен и освобожден.'");
		Иначе
			ШаблонПояснения = НСтр("ru = 'Файл ""%1""
			                             |не изменился и освобожден.'");
		КонецЕсли;
		
		ПоказатьОповещениеПользователя(
			НСтр("ru = 'Редактирование закончено'"),
			ПараметрыВыполнения.ДанныеФайла.НавигационнаяСсылка,
			СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				ШаблонПояснения, Строка(ПараметрыВыполнения.ДанныеФайла.Ссылка)),
			БиблиотекаКартинок.Информация32);
		
		Если Не ПараметрыВыполнения.ВерсияОбновлена Тогда
			Обработчик = Новый ОписаниеОповещения("ЗакончитьРедактированиеСРасширениемПослеПоказаОповещения", ЭтотОбъект, ПараметрыВыполнения);
			ПоказатьИнформациюФайлНеБылИзменен(Обработчик);
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	ЗакончитьРедактированиеСРасширениемПослеПоказаОповещения(-1, ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеСРасширениемПослеПоказаОповещения(Результат, ПараметрыВыполнения) Экспорт
	
	Если ТипЗнч(Результат) = Тип("Структура") И Результат.БольшеНеЗадаватьЭтотВопрос Тогда
		ОбщегоНазначенияВызовСервера.ХранилищеОбщихНастроекСохранить(
			"НастройкиПрограммы", "ПоказыватьИнформациюЧтоФайлНеБылИзменен", Ложь,,, Истина);
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Истина);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИРабочийКаталог
//
Процедура ЗакончитьРедактированиеСРасширениемОбработкаИсключения(ИнформацияОбОшибке, ПараметрыВыполнения)
	
	ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Не удалось поместить файл ""%1""
			|с компьютере в программу по причине:
			|%2.'"),
		Строка(ПараметрыВыполнения.ДанныеФайла.Ссылка),
		ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке));
	ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
		"Предупреждение", ТекстСообщения,, Истина);
	ТекстВопроса = ТекстСообщения + Символы.ПС + Символы.ПС + НСтр("ru = 'Повторить операцию?'");
	Обработчик = Новый ОписаниеОповещения("ЗакончитьРедактированиеСРасширениемПослеОтветаНаВопросПовторить", 
		ЭтотОбъект, ПараметрыВыполнения);
	ПоказатьВопрос(Обработчик, ТекстВопроса, РежимДиалогаВопрос.ПовторитьОтмена);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеСРасширениемПослеОтветаНаВопросПовторить(Ответ, ПараметрыВыполнения) Экспорт
	
	Если Ответ = КодВозвратаДиалога.Отмена Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	ЗакончитьРедактированиеСРасширениемПослеПроверкиЗашифрован(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеБезРасширения(ПараметрыВыполнения)
	// Веб-клиент без расширения для работы с 1С:Предприятием.
	
	Если ПараметрыВыполнения.ДанныеФайла = Неопределено Тогда
		ПараметрыДанныхФайла = РаботаСФайламиКлиентСервер.ПараметрыДанныхФайла();
		ПараметрыДанныхФайла.ПолучатьСсылкуНаДвоичныеДанные = Ложь;
		
		ПараметрыВыполнения.ДанныеФайла  = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла(ПараметрыВыполнения.ОбъектСсылка,,ПараметрыДанныхФайла);
		ПараметрыВыполнения.ХранитьВерсии                      = ПараметрыВыполнения.ДанныеФайла.ХранитьВерсии;
		ПараметрыВыполнения.ФайлРедактируетТекущийПользователь = ПараметрыВыполнения.ДанныеФайла.ФайлРедактируетТекущийПользователь;
		ПараметрыВыполнения.Редактирует                        = ПараметрыВыполнения.ДанныеФайла.Редактирует;
		ПараметрыВыполнения.АвторТекущейВерсии                 = ПараметрыВыполнения.ДанныеФайла.АвторТекущейВерсии;
		ПараметрыВыполнения.Кодировка                          = ПараметрыВыполнения.ДанныеФайла.КодировкаТекущейВерсии;
	КонецЕсли;
	
	// Проверка возможности освобождения файла.
	ТекстОшибки = "";
	МожноОсвободитьФайл = ВозможностьОсвободитьФайл(
		ПараметрыВыполнения.ОбъектСсылка,
		ПараметрыВыполнения.ФайлРедактируетТекущийПользователь,
		ПараметрыВыполнения.Редактирует,
		ТекстОшибки);
	Если Не МожноОсвободитьФайл Тогда
		ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, ТекстОшибки, Ложь);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.Вставить("ПолныйПутьКФайлу", "");
	
	Если ПараметрыВыполнения.СоздатьНовуюВерсию = Неопределено Тогда
		
		ПараметрыВыполнения.СоздатьНовуюВерсию = Истина;
		СоздатьНовуюВерсиюДоступность = Истина;
		
		Если ПараметрыВыполнения.ХранитьВерсии Тогда
			ПараметрыВыполнения.СоздатьНовуюВерсию = Истина;
			
			// Если автор текущей версии не текущий пользователь, тогда
			// отключается доступность флажка "Не создавать новую версию".
			Если ПараметрыВыполнения.АвторТекущейВерсии <> ПараметрыВыполнения.Редактирует Тогда
				СоздатьНовуюВерсиюДоступность = Ложь;
			Иначе
				СоздатьНовуюВерсиюДоступность = Истина;
			КонецЕсли;
		Иначе
			ПараметрыВыполнения.СоздатьНовуюВерсию = Ложь;
			СоздатьНовуюВерсиюДоступность = Ложь;
		КонецЕсли;
		
		СтруктураПараметров = Новый Структура;
		СтруктураПараметров.Вставить("ФайлСсылка",                    ПараметрыВыполнения.ОбъектСсылка);
		СтруктураПараметров.Вставить("КомментарийКВерсии",            "");
		СтруктураПараметров.Вставить("СоздатьНовуюВерсию",            ПараметрыВыполнения.СоздатьНовуюВерсию);
		СтруктураПараметров.Вставить("СоздатьНовуюВерсиюДоступность", СоздатьНовуюВерсиюДоступность);
		
		Обработчик = Новый ОписаниеОповещения("ЗакончитьРедактированиеБезРасширенияПослеПомещенияФайлаНаСервер", ЭтотОбъект, ПараметрыВыполнения);
		
		ОткрытьФорму("Обработка.РаботаСФайлами.Форма.ФормаВозвратаФайла", СтруктураПараметров, , , , , Обработчик);
		
	Иначе // Параметры СоздатьНовуюВерсию и КомментарийКВерсии переданы извне.
		
		Если ПараметрыВыполнения.ХранитьВерсии Тогда
			
			// Если автор текущей версии не текущий пользователь, тогда
			// отключается доступность флажка "Не создавать новую версию".
			Если ПараметрыВыполнения.АвторТекущейВерсии <> ПараметрыВыполнения.Редактирует Тогда
				ПараметрыВыполнения.СоздатьНовуюВерсию = Истина;
			КонецЕсли;
			
		Иначе
			ПараметрыВыполнения.СоздатьНовуюВерсию = Ложь;
		КонецЕсли;
		
		ЗакончитьРедактированиеБезРасширенияПослеПроверкиНовойВерсии(ПараметрыВыполнения)
		
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеБезРасширенияПослеПомещенияФайлаНаСервер(Результат, ПараметрыВыполнения) Экспорт
	
	Если ТипЗнч(Результат) <> Тип("Структура") Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	Если Результат.КодВозврата <> КодВозвратаДиалога.ОК Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.СоздатьНовуюВерсию = Результат.СоздатьНовуюВерсию;
	ПараметрыВыполнения.КомментарийКВерсии = Результат.КомментарийКВерсии;
	
	ЗакончитьРедактированиеБезРасширенияПослеПроверкиНовойВерсии(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеБезРасширенияПослеПроверкиНовойВерсии(ПараметрыВыполнения)
	
	Обработчик = Новый ОписаниеОповещения("ЗакончитьРедактированиеБезРасширенияПослеНапоминания", ЭтотОбъект, ПараметрыВыполнения);
	ПоказатьНапоминаниеПередПоместитьФайл(Обработчик);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеБезРасширенияПослеНапоминания(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат = КодВозвратаДиалога.Отмена Или Результат = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(Результат) = Тип("Структура") И Результат.Свойство("БольшеНеЗадаватьЭтотВопрос") И Результат.БольшеНеЗадаватьЭтотВопрос Тогда
		ОбщегоНазначенияВызовСервера.ХранилищеОбщихНастроекСохранить(
			"НастройкиПрограммы", "ПоказыватьПодсказкиПриРедактированииФайлов", Ложь,,, Истина);
	КонецЕсли;
	
	Обработчик = Новый ОписаниеОповещения("ЗакончитьРедактированиеБезРасширенияПослеЗагрузкиФайла", ЭтотОбъект, ПараметрыВыполнения);
	НачатьПомещениеФайла(Обработчик, , ПараметрыВыполнения.ПолныйПутьКФайлу, , ПараметрыВыполнения.ИдентификаторФормы);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеБезРасширенияПослеЗагрузкиФайла(Помещен, Адрес, ВыбранноеИмяФайла, ПараметрыВыполнения) Экспорт
	
	Если Не Помещен Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.Вставить("АдресЗагруженногоФайла", Адрес);
	ПараметрыВыполнения.Вставить("ВыбранноеИмяФайла", ВыбранноеИмяФайла);
	
	Если ПараметрыВыполнения.ДанныеФайла = Неопределено Тогда
		ПараметрыДанныхФайла = РаботаСФайламиКлиентСервер.ПараметрыДанныхФайла();
		ПараметрыДанныхФайла.ПолучатьСсылкуНаДвоичныеДанные = Ложь;
		ДанныеФайла = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла(ПараметрыВыполнения.ОбъектСсылка,,ПараметрыДанныхФайла);
	Иначе
		ДанныеФайла = ПараметрыВыполнения.ДанныеФайла;
	КонецЕсли;
	Если Не ДанныеФайла.Зашифрован Тогда
		ЗакончитьРедактированиеБезРасширенияПослеШифрованияФайла(Null, ПараметрыВыполнения);
		Возврат;
	КонецЕсли;
	Если СертификатыНеУказаны(ДанныеФайла.МассивСертификатовШифрования) Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	// Не нужно ПредложитьУстановкуРасширенияРаботыСФайлами(), т.к. все делается в памяти через ДвоичныеДанные.
	
	ОписаниеДанных = Новый Структура;
	ОписаниеДанных.Вставить("Операция",            НСтр("ru = 'Шифрование файла'"));
	ОписаниеДанных.Вставить("ЗаголовокДанных",     НСтр("ru = 'Файл'"));
	ОписаниеДанных.Вставить("Данные",              Адрес);
	ОписаниеДанных.Вставить("Представление",       ПараметрыВыполнения.ОбъектСсылка);
	ОписаниеДанных.Вставить("НаборСертификатов",   ПараметрыВыполнения.ОбъектСсылка);
	ОписаниеДанных.Вставить("БезПодтверждения",    Истина);
	ОписаниеДанных.Вставить("СообщитьОЗавершении", Ложь);
	
	ОбработчикПродолжения = Новый ОписаниеОповещения("ЗакончитьРедактированиеБезРасширенияПослеШифрованияФайла",
		ЭтотОбъект, ПараметрыВыполнения);
	
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	МодульЭлектроннаяПодписьКлиент.Зашифровать(ОписаниеДанных, , ОбработчикПродолжения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИРабочийКаталог
//
Процедура ЗакончитьРедактированиеБезРасширенияПослеШифрованияФайла(ОписаниеДанных, ПараметрыВыполнения) Экспорт
	
	Если ОписаниеДанных = Null Тогда
		Адрес = ПараметрыВыполнения.АдресЗагруженногоФайла;
		
	ИначеЕсли Не ОписаниеДанных.Успех Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	Иначе
		Если ТипЗнч(ОписаниеДанных.ЗашифрованныеДанные) = Тип("ДвоичныеДанные") Тогда
			Адрес = ПоместитьВоВременноеХранилище(ОписаниеДанных.ЗашифрованныеДанные,
				ПараметрыВыполнения.ИдентификаторФормы);
		Иначе
			Адрес = ОписаниеДанных.ЗашифрованныеДанные;
		КонецЕсли;
	КонецЕсли;
	
	СведенияОФайле = РаботаСФайламиКлиентСервер.СведенияОФайле("ФайлСВерсией");
	
	СведенияОФайле.АдресВременногоХранилищаФайла = Адрес;
	СведенияОФайле.Комментарий = ПараметрыВыполнения.КомментарийКВерсии;
	
	СтруктураПути = ОбщегоНазначенияКлиентСервер.РазложитьПолноеИмяФайла(ПараметрыВыполнения.ВыбранноеИмяФайла);
	Если Не ПустаяСтрока(СтруктураПути.Расширение) Тогда
		СведенияОФайле.РасширениеБезТочки = ОбщегоНазначенияКлиентСервер.РасширениеБезТочки(СтруктураПути.Расширение);
		СведенияОФайле.ИмяБезРасширения = СтруктураПути.ИмяБезРасширения;
	КонецЕсли;
	СведенияОФайле.ХранитьВерсии = ПараметрыВыполнения.СоздатьНовуюВерсию;
	
	Попытка
		Результат = РаботаСФайламиСлужебныйВызовСервера.СохранитьИзмененияИОсвободитьФайлПоСсылке(ПараметрыВыполнения.ОбъектСсылка,
			СведенияОФайле, ПараметрыВыполнения.ПолныйПутьКФайлу, РабочийКаталогПользователя(), 
			ПараметрыВыполнения.ИдентификаторФормы);
		ПараметрыВыполнения.ДанныеФайла = Результат.ДанныеФайла;
	Исключение
		ЗакончитьРедактированиеОбработчикИсключения(ИнформацияОбОшибке(), ПараметрыВыполнения);
		Возврат;
	КонецПопытки;
	
	ИзменитьКоличествоЗанятыхФайлов();
	
	Если ПараметрыВыполнения.ПоказыватьОповещение Тогда
		Если Результат.Успешно Тогда
			ШаблонПояснения = НСтр("ru = 'Файл ""%1""
			                             |обновлен и освобожден.'");
		Иначе
			ШаблонПояснения = НСтр("ru = 'Файл ""%1""
			                             |не изменился и освобожден.'");
		КонецЕсли;
		
		ПоказатьОповещениеПользователя(
			НСтр("ru = 'Редактирование закончено'"),
			ПараметрыВыполнения.ДанныеФайла.НавигационнаяСсылка,
			СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				ШаблонПояснения, Строка(ПараметрыВыполнения.ДанныеФайла.Ссылка)),
			БиблиотекаКартинок.Информация32);
		
		Если Не Результат.Успешно Тогда
			Обработчик = Новый ОписаниеОповещения("ЗакончитьРедактированиеБезРасширенияПослеПоказаОповещения", ЭтотОбъект, ПараметрыВыполнения);
			ПоказатьИнформациюФайлНеБылИзменен(Обработчик);
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	ЗакончитьРедактированиеБезРасширенияПослеПоказаОповещения(-1, ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеБезРасширенияПослеПоказаОповещения(Результат, ПараметрыВыполнения) Экспорт
	
	Если ТипЗнч(Результат) = Тип("Структура") И Результат.Свойство("БольшеНеЗадаватьЭтотВопрос") И Результат.БольшеНеЗадаватьЭтотВопрос Тогда
		ОбщегоНазначенияВызовСервера.ХранилищеОбщихНастроекСохранить(
			"НастройкиПрограммы","ПоказыватьИнформациюЧтоФайлНеБылИзменен", Ложь,,, Истина);
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Истина);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеОбработчикИсключения(ИнформацияОбОшибке, ПараметрыВыполнения)
	
	ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Не удалось поместить файл ""%1""
		           |с компьютера в программу по причине
		           |""%2"".
		           |
		           |Повторить операцию?'"),
		Строка(ПараметрыВыполнения.ОбъектСсылка),
		ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
	
	Обработчик = Новый ОписаниеОповещения("ЗакончитьРедактированиеБезРасширенияПослеОтветаНаВопросПовторить", ЭтотОбъект, ПараметрыВыполнения);
	ПоказатьВопрос(Обработчик, ТекстОшибки, РежимДиалогаВопрос.ПовторитьОтмена);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеБезРасширенияПослеОтветаНаВопросПовторить(Ответ, ПараметрыВыполнения) Экспорт
	Если Ответ = КодВозвратаДиалога.Отмена Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
	Иначе
		ЗакончитьРедактированиеБезРасширенияПослеПроверкиНовойВерсии(ПараметрыВыполнения);
	КонецЕсли;
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Выбор файла и создание из него новой версии.

// Загружает файл и создает новую версию.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей
//                       результат работы метода, с параметрами:
//    * Результат               - Булево - Истина, если файл обновлен.
//    * ДополнительныеПараметры - Произвольный - значение, которое было указано при создании объекта
//                              ОписаниеОповещения.
//  ДанныеФайла        - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИРабочийКаталог
//  ИдентификаторФормы - УникальныйИдентификатор - уникальный идентификатор формы.
//
Процедура ОбновитьИзФайлаНаДиске(ОбработчикРезультата, ДанныеФайла, ИдентификаторФормы,
	ПараметрыДобавленияФайла = Неопределено)
	
	Если Не РасширениеРаботыСФайламиПодключено() Тогда
		ВернутьРезультат(ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
		
	Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
	
	Если Не ПустаяСтрока(ДанныеФайла.РабочийКаталогВладельца) Тогда
		ПутьВыбора = ДанныеФайла.РабочийКаталогВладельца;
	Иначе
		ПутьВыбора = ОбщегоНазначенияВызовСервера.ХранилищеОбщихНастроекЗагрузить("НастройкиПрограммы", "ПапкаДляОбновитьИзФайла");
	КонецЕсли;
	
	Если ПутьВыбора = Неопределено Или ПутьВыбора = "" Тогда
		ПутьВыбора = КаталогМоиДокументы();
	КонецЕсли;
	
	Диалог.Заголовок                   = НСтр("ru = 'Выбор файла'");
	Диалог.ПредварительныйПросмотр     = Ложь;
	Диалог.ПроверятьСуществованиеФайла = Ложь;
	Диалог.МножественныйВыбор          = Ложь;
	Диалог.Каталог                     = ПутьВыбора;
	
	Диалог.ПолноеИмяФайла = ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(
		ДанныеФайла.ПолноеНаименованиеВерсии, ДанныеФайла.Расширение);
	
	Если ПараметрыДобавленияФайла <> Неопределено
		И ПараметрыДобавленияФайла.Свойство("ФильтрДиалогаВыбора")
		И Не ПустаяСтрока(ПараметрыДобавленияФайла.ФильтрДиалогаВыбора) Тогда
		
		Диалог.Фильтр = ПараметрыДобавленияФайла.ФильтрДиалогаВыбора;
		
	Иначе
		
		РасширениеДляЗашифрованныхФайлов = "";
		
		Если ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
			МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
			
			Если МодульЭлектроннаяПодписьКлиент.ИспользоватьШифрование() Тогда
				РасширениеДляЗашифрованныхФайлов =
					МодульЭлектроннаяПодписьКлиент.ПерсональныеНастройки().РасширениеДляЗашифрованныхФайлов;
			КонецЕсли;
		КонецЕсли;
		
		Если ЗначениеЗаполнено(РасширениеДляЗашифрованныхФайлов) Тогда
			Фильтр = НСтр("ru = 'Файл (*.%1)|*.%1|Зашифрованный файл (*.%2)|*.%2'") + "|"
					+ СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Все файлы (%1)|%1'"), ПолучитьМаскуВсеФайлы());
			Диалог.Фильтр = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Фильтр, ДанныеФайла.Расширение, РасширениеДляЗашифрованныхФайлов);
		Иначе
			Фильтр = НСтр("ru = 'Файл (*.%1)|*.%1'") + "|"
					+ СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Все файлы (%1)|%1'"), ПолучитьМаскуВсеФайлы());
			Диалог.Фильтр = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Фильтр, ДанныеФайла.Расширение);
		КонецЕсли;
		
	КонецЕсли;
	
	Если Не Диалог.Выбрать() Тогда
		ВернутьРезультат(ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	ПутьВыбораПрежний = ПутьВыбора;
	ФайлНаДиске = Новый Файл(Диалог.ПолноеИмяФайла);
	
	Если ПараметрыДобавленияФайла <> Неопределено
		И ПараметрыДобавленияФайла.Свойство("МаксимальныйРазмер")
		И ПараметрыДобавленияФайла.МаксимальныйРазмер > 0
		И ФайлНаДиске.Размер() > ПараметрыДобавленияФайла.МаксимальныйРазмер*1024*1024 Тогда
		
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Размер файла превышает %1 Мб.'"), ПараметрыДобавленияФайла.МаксимальныйРазмер);
		ВернутьРезультатПослеПоказаПредупреждения(ОбработчикРезультата, ТекстОшибки, Ложь);
		Возврат;
		
	КонецЕсли;
	
	ПутьВыбора = ФайлНаДиске.Путь;
	Если ПустаяСтрока(ДанныеФайла.РабочийКаталогВладельца) Тогда
		Если ПутьВыбораПрежний <> ПутьВыбора Тогда
			ОбщегоНазначенияВызовСервера.ХранилищеОбщихНастроекСохранить("НастройкиПрограммы", "ПапкаДляОбновитьИзФайла",  ПутьВыбора);
		КонецЕсли;
	КонецЕсли;
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("ДанныеФайла",          ДанныеФайла);
	ПараметрыВыполнения.Вставить("ИдентификаторФормы",   ИдентификаторФормы);
	ПараметрыВыполнения.Вставить("ДиалогПолноеИмяФайла", Диалог.ПолноеИмяФайла);
	ПараметрыВыполнения.Вставить("СоздатьНовуюВерсию",   Неопределено);
	ПараметрыВыполнения.Вставить("КомментарийКВерсии",   Неопределено);
	
	ПараметрыВыполнения.Вставить("ФайлНаДиске", Новый Файл(ПараметрыВыполнения.ДиалогПолноеИмяФайла));
	ПараметрыВыполнения.Вставить("ИмяИРасширениеФайлаНаДиске", ПараметрыВыполнения.ФайлНаДиске.Имя);
	ПараметрыВыполнения.Вставить("ИмяФайла", ПараметрыВыполнения.ФайлНаДиске.ИмяБезРасширения);
	
	ПараметрыВыполнения.Вставить("ВремяИзмененияВыбранное",
		ПараметрыВыполнения.ФайлНаДиске.ПолучитьУниверсальноеВремяИзменения());
	
	ПараметрыВыполнения.Вставить("РасширениеФайлаНаДиске",
		ОбщегоНазначенияКлиентСервер.РасширениеБезТочки(ПараметрыВыполнения.ФайлНаДиске.Расширение));
	
	ПараметрыВыполнения.Вставить("РасширениеДляЗашифрованныхФайлов", РасширениеДляЗашифрованныхФайлов);
	
	ПараметрыВыполнения.Вставить("ФайлЗашифрован", НРег(ПараметрыВыполнения.РасширениеФайлаНаДиске)
		= НРег(ПараметрыВыполнения.РасширениеДляЗашифрованныхФайлов));
		
	ПроверитьВозможностьЗагрузкиФайла(ФайлНаДиске);
	Если Не ПараметрыВыполнения.ФайлЗашифрован Тогда
		ОбновитьИзФайлаНаДискеПродолжение(ПараметрыВыполнения);
		Возврат;
	КонецЕсли;
	
	// отрезаем .p7m в конце
	Позиция = СтрНайти(ПараметрыВыполнения.ИмяИРасширениеФайлаНаДиске, ПараметрыВыполнения.РасширениеФайлаНаДиске);
	ПараметрыВыполнения.ИмяИРасширениеФайлаНаДиске = Лев(ПараметрыВыполнения.ИмяИРасширениеФайлаНаДиске, Позиция - 2);
	
	// отрезаем .p7m в конце
	ПараметрыВыполнения.Вставить("ДиалогПолноеИмяФайлаПрежнее", ПараметрыВыполнения.ДиалогПолноеИмяФайла);
	Позиция = СтрНайти(ПараметрыВыполнения.ДиалогПолноеИмяФайла, ПараметрыВыполнения.РасширениеФайлаНаДиске);
	ПараметрыВыполнения.ДиалогПолноеИмяФайла = Лев(ПараметрыВыполнения.ДиалогПолноеИмяФайла, Позиция - 2);
	
	ВременныйФайлНешифрованный = Новый Файл(ПараметрыВыполнения.ДиалогПолноеИмяФайла);
	
	ПараметрыВыполнения.РасширениеФайлаНаДиске = ОбщегоНазначенияКлиентСервер.РасширениеБезТочки(
		ВременныйФайлНешифрованный.Расширение);
	
	// Тут расшифровать и поставить ту же дату изменения, что и ДиалогПолноеИмяФайлаПрежнее.
	
	ПомещаемыеФайлы = Новый Массив;
	ОписаниеФайла = Новый ОписаниеПередаваемогоФайла(ПараметрыВыполнения.ДиалогПолноеИмяФайлаПрежнее);
	ПомещаемыеФайлы.Добавить(ОписаниеФайла);
	
	НачатьПомещениеФайлов(Новый ОписаниеОповещения("ОбновитьИзФайлаНаДискеПередРасшифровкой", ЭтотОбъект, ПараметрыВыполнения),
		ПомещаемыеФайлы, , Ложь, ПараметрыВыполнения.ИдентификаторФормы);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИРабочийКаталог
//
Процедура ОбновитьИзФайлаНаДискеПередРасшифровкой(ПомещаемыеФайлы, ПараметрыВыполнения) Экспорт
	
	Если Не ЗначениеЗаполнено(ПомещаемыеФайлы) Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		Возврат;
	КонецЕсли;
	
	ОписаниеДанных = Новый Структура;
	ОписаниеДанных.Вставить("Операция",              НСтр("ru = 'Расшифровка файла'"));
	ОписаниеДанных.Вставить("ЗаголовокДанных",       НСтр("ru = 'Файл'"));
	ОписаниеДанных.Вставить("Данные",                ПомещаемыеФайлы[0].Хранение);
	ОписаниеДанных.Вставить("Представление",         ПараметрыВыполнения.ДанныеФайла.Ссылка);
	ОписаниеДанных.Вставить("СертификатыШифрования", Новый Массив);
	ОписаниеДанных.Вставить("СообщитьОЗавершении",   Ложь);
	
	ОбработчикПродолжения = Новый ОписаниеОповещения("ОбновитьИзФайлаНаДискеПослеРасшифровки",
		ЭтотОбъект, ПараметрыВыполнения);
	
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	МодульЭлектроннаяПодписьКлиент.Расшифровать(ОписаниеДанных, , ОбработчикПродолжения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ОбновитьИзФайлаНаДискеПослеРасшифровки(ОписаниеДанных, ПараметрыВыполнения) Экспорт
	
	Если Не ОписаниеДанных.Успех Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(ОписаниеДанных.РасшифрованныеДанные) = Тип("ДвоичныеДанные") Тогда
		АдресФайла = ПоместитьВоВременноеХранилище(ОписаниеДанных.РасшифрованныеДанные,
			ПараметрыВыполнения.ИдентификаторФормы);
	Иначе
		АдресФайла = ОписаниеДанных.РасшифрованныеДанные;
	КонецЕсли;
	
	ПараметрыВыполнения.Вставить("АдресФайла", АдресФайла);
	
	ПередаваемыеФайлы = Новый Массив;
	ОписаниеФайла = Новый ОписаниеПередаваемогоФайла(ПараметрыВыполнения.ДиалогПолноеИмяФайла, АдресФайла);
	ПередаваемыеФайлы.Добавить(ОписаниеФайла);
	
	Если Не ПолучитьФайлы(ПередаваемыеФайлы, , , Ложь) Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	УстановитьУниверсальноеВремяИзменения(ПараметрыВыполнения.ДиалогПолноеИмяФайла, 
		ПараметрыВыполнения.ВремяИзмененияВыбранное);
	
	ПараметрыВыполнения.ФайлЗашифрован = Ложь;
	
	ОбновитьИзФайлаНаДискеПродолжение(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИРабочийКаталог
//
Процедура ОбновитьИзФайлаНаДискеПродолжение(ПараметрыВыполнения)
	
	ПараметрыВыполнения.ДанныеФайла = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИРабочийКаталог(ПараметрыВыполнения.ДанныеФайла.Ссылка);
	ПредыдущаяВерсия = ПараметрыВыполнения.ДанныеФайла.Версия;
	ИмяИРасширениеФайлаВБазе = ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(
		ПараметрыВыполнения.ДанныеФайла.ПолноеНаименованиеВерсии, ПараметрыВыполнения.ДанныеФайла.Расширение);
	ОбщегоНазначенияСлужебныйКлиент.СократитьИмяФайла(ИмяИРасширениеФайлаВБазе);
	ПараметрыВыполнения.Вставить("ДатаФайлаВБазе", ПараметрыВыполнения.ДанныеФайла.ДатаМодификацииУниверсальная);
	
	Если ПараметрыВыполнения.ВремяИзмененияВыбранное < ПараметрыВыполнения.ДатаФайлаВБазе Тогда // В хранилище более новый.
		
#Если МобильныйКлиент Тогда
		ШаблонТекстаВопроса = НСтр("ru = 'Загружаемый файл с устройства ""%1"" 
			|имеет более раннюю дату изменения, чем файл в программе:
			|
			|%2 изменен загружаемый файл;
			|%3 изменен файл в программе.
			|
			|Заменить файл более старой версией с устройства?'");
#Иначе
		ШаблонТекстаВопроса = НСтр("ru = 'Загружаемый файл с компьютера ""%1"" 
			|имеет более раннюю дату изменения, чем файл в программе:
			|
			|%2 изменен загружаемый файл;
			|%3 изменен файл в программе.
			|
			|Заменить файл более старой версией с компьютера?'");
#КонецЕсли
		ТекстВопроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонТекстаВопроса,
			Строка(ПараметрыВыполнения.ДанныеФайла.Ссылка),
			МестноеВремя(ПараметрыВыполнения.ВремяИзмененияВыбранное),
			МестноеВремя(ПараметрыВыполнения.ДатаФайлаВБазе));
		
		ОписаниеОповещения = Новый ОписаниеОповещения("ОбновитьИзФайлаНаДискеСтараяВерсия", ЭтотОбъект, ПараметрыВыполнения);
		ПоказатьВопрос(ОписаниеОповещения, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
		Возврат;

	КонецЕсли;
	
	// Проверка редактирования копии файла в рабочем каталоге.
	ВРабочемКаталогеНаЧтение = Истина;
	ВРабочемКаталогеВладельца = Ложь;
	ПолноеИмяФайла = "";
	ФайлВРабочемКаталоге = ФайлНаходитсяВЛокальномКэшеФайлов(Неопределено, ПредыдущаяВерсия,
		ПолноеИмяФайла, ВРабочемКаталогеНаЧтение, ВРабочемКаталогеВладельца);
	
#Если Не ВебКлиент И НЕ МобильныйКлиент Тогда
	Если ПараметрыВыполнения.ДанныеФайла.ФайлРедактируетТекущийПользователь И ФайлВРабочемКаталоге Тогда
		// Проверка, что файл не занят приложением.
		Попытка
			ВыбранныйФайл = Новый Файл(ПолноеИмяФайла);
			ТолькоЧтение = ВыбранныйФайл.ПолучитьТолькоЧтение();
			ВыбранныйФайл.УстановитьТолькоЧтение(Не ТолькоЧтение);
			ВыбранныйФайл.УстановитьТолькоЧтение(ТолькоЧтение);
		Исключение
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Файл ""%1"" открыт для редактирования.
					|Сначала необходимо закончить редактирование, а затем повторить действие.'"),
				ПолноеИмяФайла);
			ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, ТекстОшибки, Неопределено);
			Возврат;
		КонецПопытки;
	КонецЕсли;
#КонецЕсли
		
	Если ФайлВРабочемКаталоге И ПараметрыВыполнения.ИмяИРасширениеФайлаНаДиске <> ИмяИРасширениеФайлаВБазе Тогда
		Обработчик = Новый ОписаниеОповещения("ОбновитьИзФайлаНаДискеПослеУдаленияФайлаИзРабочегоКаталога", ЭтотОбъект, ПараметрыВыполнения);
		УдалитьФайлИзРабочегоКаталога(Обработчик, ПараметрыВыполнения.ДанныеФайла.ТекущаяВерсия, Истина);
		Возврат;
	КонецЕсли;
	
	ОбновитьИзФайлаНаДискеПослеУдаленияФайлаИзРабочегоКаталога(-1, ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИРабочийКаталог
//
Процедура ОбновитьИзФайлаНаДискеСтараяВерсия(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат <> КодВозвратаДиалога.Да Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.ВремяИзмененияВыбранное = ПараметрыВыполнения.ДатаФайлаВБазе;
	ОбновитьИзФайлаНаДискеПродолжение(ПараметрыВыполнения);
		
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИРабочийКаталог
//
Процедура ОбновитьИзФайлаНаДискеПослеУдаленияФайлаИзРабочегоКаталога(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат <> -1 Тогда
		Если Результат.Успех <> Истина Тогда
			ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	ПараметрыВыполнения.Вставить("ФайлРедактируетТекущийПользователь", 
		ПараметрыВыполнения.ДанныеФайла.ФайлРедактируетТекущийПользователь);
	Если Не ПараметрыВыполнения.ДанныеФайла.ФайлРедактируетТекущийПользователь Тогда
		
		ТекстОшибки = "";
		МожноЗанятьФайл = РаботаСФайламиКлиентСервер.МожноЛиЗанятьФайл(ПараметрыВыполнения.ДанныеФайла, ТекстОшибки);
		Если Не МожноЗанятьФайл Тогда
			ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, ТекстОшибки, Неопределено);
			Возврат;
		КонецЕсли;
		
		ТекстОшибки = "";
		
		ПараметрыЗанятияФайла = РаботаСФайламиСлужебныйКлиентСервер.ПараметрыЗанятияФайла();
		ПараметрыЗанятияФайла.УникальныйИдентификатор = ПараметрыВыполнения.ИдентификаторФормы;
		ПараметрыЗанятияФайла.ВызыватьИсключение = Ложь;
		
		ФайлЗанят = РаботаСФайламиСлужебныйВызовСервера.ЗанятьФайл(ПараметрыВыполнения.ДанныеФайла, ТекстОшибки, 
			ПараметрыЗанятияФайла);
		Если Не ФайлЗанят Тогда 
			ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, ТекстОшибки, Неопределено);
			Возврат;
		КонецЕсли;
		
		НаЧтение = Ложь;
		ВРабочемКаталогеВладельца = ПараметрыВыполнения.ДанныеФайла.РабочийКаталогВладельца <> "";
		ПеререгистрироватьФайлВРабочемКаталоге(ПараметрыВыполнения.ДанныеФайла, НаЧтение, ВРабочемКаталогеВладельца);
		
	КонецЕсли;
	
	НовоеПолноеИмяФайла = "";
	ПараметрыВыполнения.ДанныеФайла.Вставить("ПутьОбновленияИзФайлаНаДиске", ПараметрыВыполнения.ДиалогПолноеИмяФайла);
	ПараметрыВыполнения.ДанныеФайла.Расширение = ОбщегоНазначенияКлиентСервер.РасширениеБезТочки(
		ПараметрыВыполнения.РасширениеФайлаНаДиске);
	
	// Помещаем в рабочий каталог выбранный файл, т.к. указано свойство ПутьОбновленияИзФайлаНаДиске.
	Обработчик = Новый ОписаниеОповещения("ОбновитьИзФайлаНаДискеПослеПолученияФайлаВРабочийКаталог", ЭтотОбъект, 
		ПараметрыВыполнения);
	ПолучитьФайлВерсииВРабочийКаталог(Обработчик, ПараметрыВыполнения.ДанныеФайла, НовоеПолноеИмяФайла, 
		ПараметрыВыполнения.ИдентификаторФормы);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИРабочийКаталог
//
Процедура ОбновитьИзФайлаНаДискеПослеПолученияФайлаВРабочийКаталог(Результат, ПараметрыВыполнения) Экспорт
	
	// Обработка результата не требуется.
	Если ПараметрыВыполнения.ФайлЗашифрован Тогда
		РаботаСФайламиСлужебныйВызовСервера.УстановитьПризнакЗашифрован(ПараметрыВыполнения.ДанныеФайла.Ссылка, ПараметрыВыполнения.ФайлЗашифрован);
	КонецЕсли;
	
	ПереданныйПолныйПутьКФайлу = "";
	
	Обработчик = Новый ОписаниеОповещения("ОбновитьИзФайлаНаДискеПослеЗавершенияРедактирования", ЭтотОбъект, ПараметрыВыполнения);
	Если ПараметрыВыполнения.ФайлРедактируетТекущийПользователь Тогда // Файл уже был занят.
		ПараметрыОбработчика = ПараметрыОбновленияФайла(Обработчик, ПараметрыВыполнения.ДанныеФайла.Ссылка, ПараметрыВыполнения.ИдентификаторФормы);
		ПараметрыОбработчика.ПереданныйПолныйПутьКФайлу = ПереданныйПолныйПутьКФайлу;
		ПараметрыОбработчика.СоздатьНовуюВерсию = ПараметрыВыполнения.СоздатьНовуюВерсию;
		ПараметрыОбработчика.КомментарийКВерсии = ПараметрыВыполнения.КомментарийКВерсии;
		СохранитьИзмененияФайла(ПараметрыОбработчика);
	Иначе
		ПараметрыОбработчика = ПараметрыОбновленияФайла(Обработчик, ПараметрыВыполнения.ДанныеФайла.Ссылка, ПараметрыВыполнения.ИдентификаторФормы);
		ПараметрыОбработчика.ХранитьВерсии = ПараметрыВыполнения.ДанныеФайла.ХранитьВерсии;
		ПараметрыОбработчика.ФайлРедактируетТекущийПользователь = ПараметрыВыполнения.ДанныеФайла.ФайлРедактируетТекущийПользователь;
		ПараметрыОбработчика.Редактирует = ПараметрыВыполнения.ДанныеФайла.Редактирует;
		ПараметрыОбработчика.АвторТекущейВерсии = ПараметрыВыполнения.ДанныеФайла.АвторТекущейВерсии;
		ПараметрыОбработчика.ПереданныйПолныйПутьКФайлу = ПереданныйПолныйПутьКФайлу;
		ПараметрыОбработчика.СоздатьНовуюВерсию = ПараметрыВыполнения.СоздатьНовуюВерсию;
		ПараметрыОбработчика.КомментарийКВерсии = ПараметрыВыполнения.КомментарийКВерсии;
		ЗакончитьРедактирование(ПараметрыОбработчика);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ОбновитьИзФайлаНаДискеПослеЗавершенияРедактирования(РезультатРедактирования, ПараметрыВыполнения) Экспорт
	
	Если ПараметрыВыполнения.ФайлЗашифрован Тогда
		УдалитьФайлБезПодтверждения(ПараметрыВыполнения.ДиалогПолноеИмяФайла);
	КонецЕсли;
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Истина);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Пометка файла как занятого для редактирования.

// Помечает файл, как занятый для редактирования.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода:
//      * Результат - Булево -  Истина, если операция выполнена успешно.
//      * ДополнительныеПараметры - Произвольный - значение, которое было указано при создании объекта
//                                ОписаниеОповещения.
//  ОбъектСсылка            - СправочникСсылка.Файлы - файл.
//  УникальныйИдентификатор - УникальныйИдентификатор - уникальный идентификатор формы.
//
Процедура ЗанятьФайлПоСсылке(ОбработчикРезультата, ОбъектСсылка, УникальныйИдентификатор = Неопределено)
	
	ПараметрыОбработчика = Новый Структура;
	ПараметрыОбработчика.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыОбработчика.Вставить("ОбъектСсылка", ОбъектСсылка);
	ПараметрыОбработчика.Вставить("УникальныйИдентификатор", УникальныйИдентификатор);
	
	Обработчик = Новый ОписаниеОповещения("ЗанятьФайлПоСсылкеПослеУстановкиРасширения", ЭтотОбъект, ПараметрыОбработчика);
	
	ПоказатьВопросОбУстановкеРасширенияРаботыСФайлами(Обработчик);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗанятьФайлПоСсылкеПослеУстановкиРасширения(РасширениеУстановлено, ПараметрыВыполнения) Экспорт
	
	ПараметрыВыполнения.Вставить("ДанныеФайла", Неопределено);
	
	ТекстОшибки = "";
	ДанныеФайлаПолученыИОнЗанят = РаботаСФайламиСлужебныйВызовСервера.ПолучитьДанныеФайлаИЗанятьФайл(
		ПараметрыВыполнения.ОбъектСсылка, ПараметрыВыполнения.ДанныеФайла, ТекстОшибки, ПараметрыВыполнения.УникальныйИдентификатор);
		
	Если Не ДанныеФайлаПолученыИОнЗанят Тогда // Если занять нельзя, тогда выводится сообщение об ошибке.
		ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, ТекстОшибки, Ложь);
		Возврат;
	КонецЕсли;
	
	Если РасширениеРаботыСФайламиПодключено() Тогда
		НаЧтение = Ложь;
		ВРабочемКаталогеВладельца = ПараметрыВыполнения.ДанныеФайла.РабочийКаталогВладельца <> "";
		ПеререгистрироватьФайлВРабочемКаталоге(ПараметрыВыполнения.ДанныеФайла, НаЧтение, ВРабочемКаталогеВладельца);
	КонецЕсли;
	
	ДанныеФайла = ПараметрыВыполнения.ДанныеФайла; // см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
	ПоказатьОповещениеПользователя(
		НСтр("ru = 'Редактирование файла'"),
		ПараметрыВыполнения.ДанныеФайла.НавигационнаяСсылка,
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Файл ""%1""
			           |занят для редактирования.'"), Строка(ДанныеФайла.Ссылка)),
		БиблиотекаКартинок.Информация32);
	
	ИзменитьКоличествоЗанятыхФайлов(1);
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Истина);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Пометка файлов как занятых для редактирования.

// Помечает файлы, как занятые для редактирования.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  МассивФайлов - Массив - массив файлов.
//
Процедура ЗанятьФайлыПоСсылкам(ОбработчикРезультата, Знач МассивФайлов)
	
	ПараметрыОбработчика = Новый Структура;
	ПараметрыОбработчика.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыОбработчика.Вставить("МассивФайлов", МассивФайлов);
	
	Обработчик = Новый ОписаниеОповещения("ЗанятьФайлыПоСсылкамПослеУстановкиРасширения", ЭтотОбъект, ПараметрыОбработчика);
	
	ПоказатьВопросОбУстановкеРасширенияРаботыСФайлами(Обработчик);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗанятьФайлыПоСсылкамПослеУстановкиРасширения(РасширениеУстановлено, ПараметрыВыполнения) Экспорт
	
	// Получение массива данных файлов.
	ДанныеФайлов = Новый Массив;
	РаботаСФайламиСлужебныйВызовСервера.ПолучитьДанныеДляМассиваФайлов(ПараметрыВыполнения.МассивФайлов, ДанныеФайлов);
	ВГраницаМассива  = ДанныеФайлов.ВГраница();
	
	Для Инд = 0 По ВГраницаМассива Цикл
		ДанныеФайла = ДанныеФайлов[ВГраницаМассива - Инд];
		
		СтрокаОшибки = "";
		Если Не РаботаСФайламиКлиентСервер.МожноЛиЗанятьФайл(ДанныеФайла, СтрокаОшибки)
		 Или ЗначениеЗаполнено(ДанныеФайла.Редактирует) Тогда // Занять невозможно.
			
			ДанныеФайлов.Удалить(ВГраницаМассива - Инд);
		КонецЕсли;
	КонецЦикла;
	
	// Занять файлы.
	КоличествоЗанятых = 0;
	
	Для Каждого ДанныеФайла Из ДанныеФайлов Цикл
		
		Если Не РаботаСФайламиСлужебныйВызовСервера.ЗанятьФайл(ДанныеФайла, "") Тогда 
			Продолжить;
		КонецЕсли;
		
		Если РасширениеРаботыСФайламиПодключено() Тогда
			НаЧтение = Ложь;
			ВРабочемКаталогеВладельца = ДанныеФайла.РабочийКаталогВладельца <> "";
			ПеререгистрироватьФайлВРабочемКаталоге(ДанныеФайла, НаЧтение, ВРабочемКаталогеВладельца);
		КонецЕсли;
		
		КоличествоЗанятых = КоличествоЗанятых + 1;
	КонецЦикла;
	
	ПоказатьОповещениеПользователя(
		НСтр("ru = 'Занять файлы'"),
		,
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Файлы (%1 из %2) заняты для редактирования.'"),
			КоличествоЗанятых,
			ПараметрыВыполнения.МассивФайлов.Количество()),
		БиблиотекаКартинок.Информация32);
	
	ИзменитьКоличествоЗанятыхФайлов(ДанныеФайлов.Количество());
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Истина);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Открытие файла для редактирования по ссылке.

// Открывает файл для редактирования.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  ОбъектСсылка            - СправочникСсылка.Файлы - файл.
//  УникальныйИдентификатор - УникальныйИдентификатор - идентификатор формы.
//  РабочийКаталогВладельца - Строка - рабочий каталог владельца.
//
Процедура РедактироватьФайлПоСсылке(ОбработчикРезультата, ОбъектСсылка,
	УникальныйИдентификатор = Неопределено, РабочийКаталогВладельца = Неопределено)
	
	ПараметрыОбработчика = Новый Структура;
	ПараметрыОбработчика.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыОбработчика.Вставить("ОбъектСсылка", ОбъектСсылка);
	ПараметрыОбработчика.Вставить("УникальныйИдентификатор", УникальныйИдентификатор);
	ПараметрыОбработчика.Вставить("РабочийКаталогВладельца", РабочийКаталогВладельца);
	
	Обработчик = Новый ОписаниеОповещения("РедактироватьФайлПоСсылкеПослеУстановкиРасширения", ЭтотОбъект, ПараметрыОбработчика);
	ПоказатьВопросОбУстановкеРасширенияРаботыСФайлами(Обработчик);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура РедактироватьФайлПоСсылкеПослеУстановкиРасширения(РасширениеУстановлено, ПараметрыВыполнения) Экспорт
	
	ПараметрыВыполнения.Вставить("ДанныеФайла", Неопределено);
	ПараметрыВыполнения.Вставить("РасширениеПодключено", РасширениеРаботыСФайламиПодключено());
	ПараметрыВыполнения.Вставить("ФайлУжеРедактируетТекущийПользователь", Ложь);
	
	Результат = РаботаСФайламиСлужебныйВызовСервера.ЗанятьФайлДляРедактирования(ПараметрыВыполнения.ОбъектСсылка,
		ПараметрыВыполнения.УникальныйИдентификатор, ПараметрыВыполнения.РабочийКаталогВладельца);
		
	ПараметрыВыполнения.ДанныеФайла = Результат.ДанныеФайла;
	ПараметрыВыполнения.ФайлУжеРедактируетТекущийПользователь = Результат.ФайлУжеРедактируетТекущийПользователь;
	Если Не Результат.ДанныеПолучены Тогда
		СтандартнаяОбработка = Истина;
		РаботаСФайламиКлиентПереопределяемый.ПриОшибкеЗахватаФайла(ПараметрыВыполнения.ДанныеФайла, СтандартнаяОбработка);
		
		Если СтандартнаяОбработка Тогда
			// Если занять нельзя, тогда выводится сообщение об ошибке.
			ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, 
				Результат.ТекстСообщения, Ложь);
			Возврат;
		КонецЕсли;
		
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Истина);
		Возврат;
	КонецЕсли;
	
	Если Не ПараметрыВыполнения.ФайлУжеРедактируетТекущийПользователь Тогда
		ИзменитьКоличествоЗанятыхФайлов(1);
	КонецЕсли;
	
	Если ПараметрыВыполнения.РасширениеПодключено Тогда
		НаЧтение = Ложь;
		ВРабочемКаталогеВладельца = ПараметрыВыполнения.ДанныеФайла.РабочийКаталогВладельца <> "";
		ПеререгистрироватьФайлВРабочемКаталоге(ПараметрыВыполнения.ДанныеФайла, НаЧтение, ВРабочемКаталогеВладельца);
	КонецЕсли;
	
	ДанныеФайла = ПараметрыВыполнения.ДанныеФайла; // см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
	
	ПоказатьОповещениеПользователя(НСтр("ru = 'Редактирование файла'"),
		ПараметрыВыполнения.ДанныеФайла.НавигационнаяСсылка,
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Файл ""%1""
			           |занят для редактирования.'"), Строка(ДанныеФайла.Ссылка)),
			БиблиотекаКартинок.Информация32);
	
	Если ПараметрыВыполнения.ДанныеФайла.Версия.Пустая() Тогда 
		ВернутьРезультатПослеПоказаЗначения(ПараметрыВыполнения.ОбработчикРезультата, ДанныеФайла.Ссылка, Истина);
		Возврат;
	КонецЕсли;
	
	Если ПараметрыВыполнения.РасширениеПодключено Тогда
		Обработчик = Новый ОписаниеОповещения("РедактироватьФайлПоСсылкеСРасширениемПослеПолученияФайлаВРабочийКаталог", ЭтотОбъект, ПараметрыВыполнения);
		ПолучитьФайлВерсииВРабочийКаталог(Обработчик, ПараметрыВыполнения.ДанныеФайла, "",
			ПараметрыВыполнения.УникальныйИдентификатор);
	Иначе
		ЗаполнитьВременныйИдентификаторФормы(ПараметрыВыполнения.УникальныйИдентификатор, ПараметрыВыполнения);
		Обработчик = Новый ОписаниеОповещения("РедактироватьФайлПоСсылкеЗавершение", ЭтотОбъект, ПараметрыВыполнения);
		ОткрытьФайлБезРасширения(Обработчик, ПараметрыВыполнения.ДанныеФайла, ПараметрыВыполнения.УникальныйИдентификатор);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура РедактироватьФайлПоСсылкеСРасширениемПослеПолученияФайлаВРабочийКаталог(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат.ФайлПолучен = Истина Тогда
		УникальныйИдентификатор = ?(ПараметрыВыполнения.Свойство("УникальныйИдентификатор"),
			ПараметрыВыполнения.УникальныйИдентификатор, Неопределено);
		ОткрытьФайлПриложением(ПараметрыВыполнения.ДанныеФайла, Результат.ПолноеИмяФайла, УникальныйИдентификатор);
	КонецЕсли;
	
	ФайлУжеРедактируетТекущийПользователь = Ложь;
	Если Не ПараметрыВыполнения.ФайлУжеРедактируетТекущийПользователь Тогда
		ФайлУжеРедактируетТекущийПользователь = Истина;
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ФайлУжеРедактируетТекущийПользователь);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура РедактироватьФайлПоСсылкеЗавершение(Результат, ПараметрыВыполнения) Экспорт
	
	ОчиститьВременныйИдентификаторФормы(ПараметрыВыполнения);
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Результат = Истина);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Открытие файла для редактирования.

// Открывает файл для редактирования.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  ДанныеФайла             - Структура
//  УникальныйИдентификатор - УникальныйИдентификатор формы.
//
Процедура РедактироватьФайл(ОбработчикРезультата, ДанныеФайла, УникальныйИдентификатор = Неопределено) Экспорт
	
	ПараметрыОбработчика = Новый Структура;
	ПараметрыОбработчика.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыОбработчика.Вставить("ДанныеФайла", ДанныеФайла);
	ПараметрыОбработчика.Вставить("УникальныйИдентификатор", УникальныйИдентификатор);
	
	Обработчик = Новый ОписаниеОповещения("РедактироватьФайлПослеУстановкиРасширения", ЭтотОбъект, ПараметрыОбработчика);
	
	ПоказатьВопросОбУстановкеРасширенияРаботыСФайлами(Обработчик);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура РедактироватьФайлПослеУстановкиРасширения(РасширениеУстановлено, ПараметрыВыполнения) Экспорт
	
	ТекстОшибки = "";
	МожноЗанятьФайл = РаботаСФайламиКлиентСервер.МожноЛиЗанятьФайл(
		ПараметрыВыполнения.ДанныеФайла,
		ТекстОшибки);
	Если Не МожноЗанятьФайл Тогда
		ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, ТекстОшибки, Ложь);
		Возврат;
	КонецЕсли;
	
	// Если Файл не занят, тогда занять файл.
	Если Не ЗначениеЗаполнено(ПараметрыВыполнения.ДанныеФайла.Редактирует) Тогда
		Обработчик = Новый ОписаниеОповещения("РедактироватьФайлПослеЗанятияФайла", ЭтотОбъект, ПараметрыВыполнения);
		ЗанятьФайл(Обработчик, ПараметрыВыполнения.ДанныеФайла, ПараметрыВыполнения.УникальныйИдентификатор);
		Возврат;
	КонецЕсли;
	
	РедактироватьФайлПослеЗанятияФайла(-1, ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаДляОткрытия
//   ПараметрыВыполнения - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаДляОткрытия
//
Процедура РедактироватьФайлПослеЗанятияФайла(ДанныеФайла, ПараметрыВыполнения) Экспорт
	
	Если ДанныеФайла = Неопределено Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	Если ДанныеФайла <> -1 Тогда
		ПараметрыВыполнения.ДанныеФайла = ДанныеФайла;
	КонецЕсли;
	
	// Если Файл без файла, тогда открыть карточку.
	Если ПараметрыВыполнения.ДанныеФайла.Версия.Пустая() Тогда 
		ВернутьРезультатПослеПоказаЗначения(
			ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения.ДанныеФайла.Ссылка, Истина);
		Возврат;
	КонецЕсли;
	
	Если РасширениеРаботыСФайламиПодключено() Тогда
		Обработчик = Новый ОписаниеОповещения(
			"РедактироватьФайлСРасширениемПослеПолученияФайлаВРабочийКаталог", ЭтотОбъект, ПараметрыВыполнения);
		ПолучитьФайлВерсииВРабочийКаталог(
			Обработчик,
			ПараметрыВыполнения.ДанныеФайла,
			"",
			ПараметрыВыполнения.УникальныйИдентификатор);
	Иначе
		ЗаполнитьВременныйИдентификаторФормы(ПараметрыВыполнения.УникальныйИдентификатор, ПараметрыВыполнения);
		
		Обработчик = Новый ОписаниеОповещения("РедактироватьФайлБезРасширенияЗавершение", ЭтотОбъект, ПараметрыВыполнения);
		ОткрытьФайлБезРасширения(Обработчик, ПараметрыВыполнения.ДанныеФайла, ПараметрыВыполнения.УникальныйИдентификатор);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура РедактироватьФайлСРасширениемПослеПолученияФайлаВРабочийКаталог(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат.ФайлПолучен = Истина Тогда
		УникальныйИдентификатор = ?(ПараметрыВыполнения.Свойство("УникальныйИдентификатор"),
			ПараметрыВыполнения.УникальныйИдентификатор, Неопределено);
		ОткрытьФайлПриложением(ПараметрыВыполнения.ДанныеФайла, Результат.ПолноеИмяФайла, УникальныйИдентификатор);
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Результат.ФайлПолучен = Истина);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура РедактироватьФайлБезРасширенияЗавершение(Результат, ПараметрыВыполнения) Экспорт
	
	ОчиститьВременныйИдентификаторФормы(ПараметрыВыполнения);
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Результат = Истина);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Открытие версии файла.

// Продолжение процедуры (см. выше).
//
// Параметры:
//   РасширениеУстановлено - Булево
//   ПараметрыВыполнения - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаДляОткрытия
//
Процедура ОткрытьВерсиюФайлаПослеУстановкиРасширения(РасширениеУстановлено, ПараметрыВыполнения) Экспорт
	
	Если РасширениеРаботыСФайламиПодключено() Тогда
		Обработчик = Новый ОписаниеОповещения("ОткрытьВерсиюФайлаПослеПолученияФайлаВРабочийКаталог", ЭтотОбъект, ПараметрыВыполнения);
		ПолучитьФайлВерсииВРабочийКаталог(
			Обработчик,
			ПараметрыВыполнения.ДанныеФайла,
			"",
			ПараметрыВыполнения.УникальныйИдентификатор);
	Иначе
		Адрес = РаботаСФайламиСлужебныйВызовСервера.ПолучитьНавигационнуюСсылкуДляОткрытия(
			ПараметрыВыполнения.ДанныеФайла.Версия, ПараметрыВыполнения.УникальныйИдентификатор);
		
		ИмяФайла = ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(
			ПараметрыВыполнения.ДанныеФайла.ПолноеНаименованиеВерсии, ПараметрыВыполнения.ДанныеФайла.Расширение);
		
		ПолучитьФайл(Адрес, ИмяФайла, Истина);
		
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ОткрытьВерсиюФайлаПослеПолученияФайлаВРабочийКаталог(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат.ФайлПолучен Тогда
		УникальныйИдентификатор = ?(ПараметрыВыполнения.Свойство("УникальныйИдентификатор"),
			ПараметрыВыполнения.УникальныйИдентификатор, Неопределено);
		ОткрытьФайлПриложением(ПараметрыВыполнения.ДанныеФайла, Результат.ПолноеИмяФайла, УникальныйИдентификатор);
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Освобождение файлов без обновления.

// Освобождает файлы без обновления.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  МассивФайлов - Массив - массив файлов.
//
Процедура ОсвободитьФайлыПоСсылкам(ОбработчикРезультата, Знач МассивФайлов)
	
	ПараметрыОбработчика = Новый Структура;
	ПараметрыОбработчика.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыОбработчика.Вставить("МассивФайлов", МассивФайлов);
	
	Обработчик = Новый ОписаниеОповещения("ОсвободитьФайлыПоСсылкамПослеУстановкиРасширения", ЭтотОбъект, ПараметрыОбработчика);
	
	ПоказатьВопросОбУстановкеРасширенияРаботыСФайлами(Обработчик);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ОсвободитьФайлыПоСсылкамПослеУстановкиРасширения(РасширениеУстановлено, ПараметрыВыполнения) Экспорт
	
	// Получение массива данных файлов.
	ПараметрыВыполнения.Вставить("ДанныеФайлов", Новый Массив);
	РаботаСФайламиСлужебныйВызовСервера.ПолучитьДанныеДляМассиваФайлов(ПараметрыВыполнения.МассивФайлов, ПараметрыВыполнения.ДанныеФайлов);
	ВГраницаМассива = ПараметрыВыполнения.ДанныеФайлов.ВГраница();
	
	// Проверка возможности освобождения файлов.
	Для Инд = 0 По ВГраницаМассива Цикл
		
		ДанныеФайла = ПараметрыВыполнения.ДанныеФайлов[ВГраницаМассива - Инд]; // см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
		
		ТекстОшибки = "";
		МожноОсвободитьФайл = ВозможностьОсвободитьФайл(
			ДанныеФайла.Ссылка,
			ДанныеФайла.ФайлРедактируетТекущийПользователь,
			ДанныеФайла.Редактирует,
			ТекстОшибки);
		Если Не МожноОсвободитьФайл Тогда
			ПараметрыВыполнения.ДанныеФайлов.Удалить(ВГраницаМассива - Инд);
		КонецЕсли;
		
	КонецЦикла;
	
	Если Не РасширениеРаботыСФайламиПодключено() Тогда
		Возврат;
	КонецЕсли;
	
	Обработчик = Новый ОписаниеОповещения("ОсвободитьФайлыПоСсылкамПослеОтветаНаВопросОтменитьРедактирование", ЭтотОбъект, ПараметрыВыполнения);
	
	ПоказатьВопрос(
		Обработчик,
		НСтр("ru = 'Отмена редактирования файлов может
		           |привести к потере Ваших изменений.
		           |
		           |Продолжить?'"),
		РежимДиалогаВопрос.ДаНет,
		,
		КодВозвратаДиалога.Нет);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   Ответ - КодВозвратаДиалога
//         - Неопределено
//   ПараметрыВыполнения - Структура:
//     * ДанныеФайлов - Массив из см. РаботаСФайлами.ДанныеФайла
//
Процедура ОсвободитьФайлыПоСсылкамПослеОтветаНаВопросОтменитьРедактирование(Ответ, ПараметрыВыполнения) Экспорт
	
	Если Ответ <> КодВозвратаДиалога.Да Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
		Возврат;
	КонецЕсли;
	
	// Занятие файлов.
	Для Каждого ДанныеФайла Из ПараметрыВыполнения.ДанныеФайлов Цикл
		
		Параметры = ПараметрыОсвобожденияФайла(Неопределено, ДанныеФайла.Ссылка);
		Параметры.ХранитьВерсии = ДанныеФайла.ХранитьВерсии;
		Параметры.ФайлРедактируетТекущийПользователь = ДанныеФайла.ФайлРедактируетТекущийПользователь;
		Параметры.Редактирует = ДанныеФайла.Редактирует;
		Параметры.НеЗадаватьВопрос = Истина;
		ОсвободитьФайл(Параметры);
		
	КонецЦикла;
	
	ПоказатьОповещениеПользователя(
		НСтр("ru = 'Отменить редактирование файлов'"),,
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Отменено редактирование файлов (%1 из %2).'"),
			ПараметрыВыполнения.ДанныеФайлов.Количество(),
			ПараметрыВыполнения.МассивФайлов.Количество()),
		БиблиотекаКартинок.Информация32);
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Освобождение файла без обновления.

// Возвращаемое значение:
//   Структура:
//    * ОбработчикРезультата    - ОписаниеОповещения
//                              - Неопределено - описание процедуры, принимающей результат работы
//                                метода.
//    * ОбъектСсылка            - СправочникСсылка.Файлы - файл.
//    * Версия                  - СправочникСсылка.ВерсииФайлов - версия файла.
//    * ХранитьВерсии           - Булево - хранить версии.
//    * РедактируетТекущийПользователь - Булево - файл редактирует текущий пользователь.
//    * Редактирует             - СправочникСсылка.Пользователи - кто занял файл.
//    * УникальныйИдентификатор - УникальныйИдентификатор - идентификатор управляемой формы.
//    * НеЗадаватьВопрос        - Булево - не задавать вопрос "Отмена редактирования файла
//                                         может привести к потере Ваших изменений. Продолжить?".
//
Функция ПараметрыОсвобожденияФайла(ОбработчикРезультата, ОбъектСсылка) Экспорт
	
	ПараметрыОбработчика = Новый Структура;
	ПараметрыОбработчика.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыОбработчика.Вставить("ОбъектСсылка", ОбъектСсылка);
	ПараметрыОбработчика.Вставить("Версия");
	ПараметрыОбработчика.Вставить("ХранитьВерсии");
	ПараметрыОбработчика.Вставить("ФайлРедактируетТекущийПользователь");
	ПараметрыОбработчика.Вставить("Редактирует");
	ПараметрыОбработчика.Вставить("УникальныйИдентификатор");
	ПараметрыОбработчика.Вставить("НеЗадаватьВопрос", Ложь);
	Возврат ПараметрыОбработчика;
	
КонецФункции	

// Освобождает файл без обновления.
//
// Параметры:
//  ПараметрыОсвобожденияФайла - см. ПараметрыОсвобожденияФайла.
//
Процедура ОсвободитьФайл(ПараметрыОсвобожденияФайла)
	
	Обработчик = Новый ОписаниеОповещения("ОсвободитьФайлПослеУстановкиРасширения", ЭтотОбъект, ПараметрыОсвобожденияФайла);
	ПоказатьВопросОбУстановкеРасширенияРаботыСФайлами(Обработчик);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ОсвободитьФайлПослеУстановкиРасширения(РасширениеУстановлено, ПараметрыВыполнения) Экспорт
	
	ПараметрыВыполнения.Вставить("ДанныеФайла", Неопределено);
	ПараметрыВыполнения.Вставить("ПродолжитьРаботу", Истина);
	
	Если ПараметрыВыполнения.ХранитьВерсии = Неопределено Тогда
		ПараметрыДанныхФайла = РаботаСФайламиКлиентСервер.ПараметрыДанныхФайла();
		ПараметрыДанныхФайла.ПолучатьСсылкуНаДвоичныеДанные = Ложь;
		
		ДанныеФайла = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла(
			?(ПараметрыВыполнения.ОбъектСсылка <> Неопределено, ПараметрыВыполнения.ОбъектСсылка, ПараметрыВыполнения.Версия),,ПараметрыДанныхФайла);
		
		Если НЕ ЗначениеЗаполнено(ПараметрыВыполнения.ОбъектСсылка) Тогда
			ПараметрыВыполнения.ОбъектСсылка = ДанныеФайла.Ссылка;
		КонецЕсли;
		ПараметрыВыполнения.ХранитьВерсии                      = ДанныеФайла.ХранитьВерсии;
		ПараметрыВыполнения.ФайлРедактируетТекущийПользователь = ДанныеФайла.ФайлРедактируетТекущийПользователь;
		ПараметрыВыполнения.Редактирует                        = ДанныеФайла.Редактирует;
		
		ПараметрыВыполнения.ДанныеФайла = ДанныеФайла;
		
	КонецЕсли;
	
	// Проверка возможности освобождения файла.
	ТекстОшибки = "";
	МожноОсвободитьФайл = ВозможностьОсвободитьФайл(
		ПараметрыВыполнения.ОбъектСсылка,
		ПараметрыВыполнения.ФайлРедактируетТекущийПользователь,
		ПараметрыВыполнения.Редактирует,
		ТекстОшибки);
	
	Если Не МожноОсвободитьФайл Тогда
		ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, ТекстОшибки, Ложь);
		Возврат;
	КонецЕсли;
	
	Если ПараметрыВыполнения.НеЗадаватьВопрос = Ложь Тогда
		ПараметрыВыполнения.ОбработчикРезультата = ОбработчикЗавершения(ПараметрыВыполнения.ОбработчикРезультата);
		Обработчик = Новый ОписаниеОповещения("ОсвободитьФайлПослеОтветаНаВопросОтменаРедактирования", ЭтотОбъект, ПараметрыВыполнения);
		ТекстВопроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Отмена редактирования файла
			           |""%1""
			           |может привести к потере внесенных изменений.
			           |
			           |Продолжить?'"),
			Строка(ПараметрыВыполнения.ОбъектСсылка));
		ПоказатьВопрос(Обработчик, ТекстВопроса, РежимДиалогаВопрос.ДаНет, , КодВозвратаДиалога.Нет);
		Возврат;
	КонецЕсли;
	
	ОсвободитьФайлПослеОтветаНаВопросОтменаРедактирования(-1, ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ОсвободитьФайлПослеОтветаНаВопросОтменаРедактирования(Ответ, ПараметрыВыполнения) Экспорт
	
	Если Ответ <> -1 Тогда
		Если Ответ = КодВозвратаДиалога.Да Тогда
			ПараметрыВыполнения.ПродолжитьРаботу = Истина;
		Иначе
			ПараметрыВыполнения.ПродолжитьРаботу = Ложь;
		КонецЕсли;
	КонецЕсли;
	
	Если ПараметрыВыполнения.ПродолжитьРаботу Тогда
		
		РаботаСФайламиСлужебныйВызовСервера.ПолучитьДанныеФайлаИОсвободитьФайл(ПараметрыВыполнения.ОбъектСсылка,
			ПараметрыВыполнения.ДанныеФайла, ПараметрыВыполнения.УникальныйИдентификатор);
		ОповеститьОбИзменении(ТипЗнч(ПараметрыВыполнения.ОбъектСсылка));
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ДанныеФайлаИзменены"), ПараметрыВыполнения.ОбъектСсылка);
		
		Если РасширениеРаботыСФайламиПодключено() Тогда
			НаЧтение = Истина;
			ВРабочемКаталогеВладельца = ПараметрыВыполнения.ДанныеФайла.РабочийКаталогВладельца <> "";
			ПеререгистрироватьФайлВРабочемКаталоге(ПараметрыВыполнения.ДанныеФайла, НаЧтение, ВРабочемКаталогеВладельца);
		КонецЕсли;
		
		Если Не ПараметрыВыполнения.НеЗадаватьВопрос Тогда
			ПоказатьОповещениеПользователя(
				НСтр("ru = 'Файл освобожден'"),
				ПараметрыВыполнения.ДанныеФайла.НавигационнаяСсылка,
				ПараметрыВыполнения.ДанныеФайла.ПолноеНаименованиеВерсии,
				БиблиотекаКартинок.Информация32);
		КонецЕсли;
		
		ИзменитьКоличествоЗанятыхФайлов();
		
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Истина);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Запись изменений файла.

// Начало записи изменений файла.
//
// Параметры:
//   ПараметрыОбновленияФайла - см. ПараметрыОбновленияФайла.
//
Процедура СохранитьИзмененияФайла(ПараметрыОбновленияФайла) 
	
	Обработчик = Новый ОписаниеОповещения("СохранитьИзмененияФайлаПослеУстановкиРасширения", ЭтотОбъект, ПараметрыОбновленияФайла);
	ПоказатьВопросОбУстановкеРасширенияРаботыСФайлами(Обработчик);
		
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьИзмененияФайлаПослеУстановкиРасширения(РасширениеУстановлено, ПараметрыВыполнения) Экспорт
	
	ПараметрыВыполнения.Вставить("ДанныеФайла", Неопределено);
	ПараметрыВыполнения.Вставить("АдресВременногоХранилища", Неопределено);
	ПараметрыВыполнения.Вставить("ПолныйПутьКФайлу", Неопределено);
	
	Если РасширениеРаботыСФайламиПодключено() Тогда
		СохранитьИзмененияФайлаСРасширением(ПараметрыВыполнения);
	Иначе
		СохранитьИзмененияФайлаБезРасширения(ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьИзмененияФайлаСРасширением(ПараметрыВыполнения)
	// Код для тонкого клиента, толстого клиента и веб-клиента с подключенным расширением.
	
	ДанныеФайла = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИРабочийКаталог(ПараметрыВыполнения.ОбъектСсылка);
	ПараметрыВыполнения.ДанныеФайла = ДанныеФайла;
	ПараметрыВыполнения.ХранитьВерсии = ДанныеФайла.ХранитьВерсии;
	
	// Проверка возможности освобождения файла.
	ТекстОшибки = "";
	МожноОсвободитьФайл = ВозможностьОсвободитьФайл(
		ДанныеФайла.Ссылка,
		ДанныеФайла.ФайлРедактируетТекущийПользователь,
		ДанныеФайла.Редактирует,
		ТекстОшибки);
	Если Не МожноОсвободитьФайл Тогда
		ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, ТекстОшибки, Ложь);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.ПолныйПутьКФайлу = ПараметрыВыполнения.ПереданныйПолныйПутьКФайлу;
	Если ПараметрыВыполнения.ПолныйПутьКФайлу = "" Тогда
		ПараметрыВыполнения.ПолныйПутьКФайлу = ДанныеФайла.ПолноеИмяФайлаВРабочемКаталоге;
	КонецЕсли;
	
	// Проверка наличия файла на компьютере.
	ПараметрыВыполнения.Вставить("ФайлНовойВерсии", Новый Файл(ПараметрыВыполнения.ПолныйПутьКФайлу));
	Если Не ПараметрыВыполнения.ФайлНовойВерсии.Существует() Тогда
		Если Не ПустаяСтрока(ПараметрыВыполнения.ПолныйПутьКФайлу) Тогда
			СтрокаПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось поместить файл ""%1""
				           |в программу, так как он не существует на компьютере:
				           |%2.
				           |
				           |Освободить файл?'"),
				Строка(ДанныеФайла.Ссылка),
				ПараметрыВыполнения.ПолныйПутьКФайлу);
		Иначе
			СтрокаПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось поместить файл ""%1""
				           |в программу, так как он не существует на компьютере.
				           |
				           |Освободить файл?'"),
				Строка(ДанныеФайла.Ссылка));
		КонецЕсли;
		
		Обработчик = Новый ОписаниеОповещения("СохранитьИзмененияФайлаСРасширениемПослеОтветаНаВопросОсвободитьФайл", ЭтотОбъект, ПараметрыВыполнения);
		ПоказатьВопрос(Обработчик, СтрокаПредупреждения, РежимДиалогаВопрос.ДаНет);
		Возврат;
	КонецЕсли;
	
	// Запрос комментария и признака хранения версии.
	Если ПараметрыВыполнения.СоздатьНовуюВерсию = Неопределено Тогда
		
		ПараметрыВыполнения.СоздатьНовуюВерсию = Истина;
		СоздатьНовуюВерсиюДоступность = Истина;
		
		Если ДанныеФайла.ХранитьВерсии Тогда
			ПараметрыВыполнения.СоздатьНовуюВерсию = Истина;
			
			// Если автор текущей версии не текущий пользователь, тогда
			// отключается доступность флажка "Не создавать новую версию".
			Если ДанныеФайла.АвторТекущейВерсии <> ДанныеФайла.Редактирует Тогда
				СоздатьНовуюВерсиюДоступность = Ложь;
			Иначе
				СоздатьНовуюВерсиюДоступность = Истина;
			КонецЕсли;
		Иначе
			ПараметрыВыполнения.СоздатьНовуюВерсию = Ложь;
			СоздатьНовуюВерсиюДоступность = Ложь;
			СохранитьИзмененияФайлаСРасширениемПослеПроверкиНовойВерсии(ПараметрыВыполнения);
			Возврат;
		КонецЕсли;
		
		СтруктураПараметров = Новый Структура;
		СтруктураПараметров.Вставить("ФайлСсылка",                    ДанныеФайла.Ссылка);
		СтруктураПараметров.Вставить("КомментарийКВерсии",            "");
		СтруктураПараметров.Вставить("СоздатьНовуюВерсию",            ПараметрыВыполнения.СоздатьНовуюВерсию);
		СтруктураПараметров.Вставить("СоздатьНовуюВерсиюДоступность", СоздатьНовуюВерсиюДоступность);
		
		Обработчик = Новый ОписаниеОповещения("СохранитьИзмененияФайлаСРасширениемПослеПомещенияФайлаНаСервер", ЭтотОбъект, ПараметрыВыполнения);
		
		ОткрытьФорму("Обработка.РаботаСФайлами.Форма.ФормаВозвратаФайла", СтруктураПараметров, , , , , Обработчик);
		
	Иначе // Параметры СоздатьНовуюВерсию и КомментарийКВерсии переданы извне.
		
		Если ПараметрыВыполнения.ХранитьВерсии Тогда
			
			// Если автор текущей версии не текущий пользователь, тогда
			// отключается доступность флажка "Не создавать новую версию".
			Если ПараметрыВыполнения.АвторТекущейВерсии <> ПараметрыВыполнения.Редактирует Тогда
				ПараметрыВыполнения.СоздатьНовуюВерсию = Истина;
			КонецЕсли;
			
		Иначе
			ПараметрыВыполнения.СоздатьНовуюВерсию = Ложь;
		КонецЕсли;
		
		СохранитьИзмененияФайлаСРасширениемПослеПроверкиНовойВерсии(ПараметрыВыполнения);
		
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьИзмененияФайлаСРасширениемПослеОтветаНаВопросОсвободитьФайл(Ответ, ПараметрыВыполнения) Экспорт
	
	Если Ответ = КодВозвратаДиалога.Да Тогда
		ОсвободитьФайлБезВопроса(ПараметрыВыполнения.ДанныеФайла, ПараметрыВыполнения.ИдентификаторФормы);
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьИзмененияФайлаСРасширениемПослеПомещенияФайлаНаСервер(Результат, ПараметрыВыполнения) Экспорт
	
	Если ТипЗнч(Результат) <> Тип("Структура") Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	КодВозврата = Результат.КодВозврата;
	Если КодВозврата <> КодВозвратаДиалога.ОК Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.СоздатьНовуюВерсию = Результат.СоздатьНовуюВерсию;
	ПараметрыВыполнения.КомментарийКВерсии = Результат.КомментарийКВерсии;
	
	СохранитьИзмененияФайлаСРасширениемПослеПроверкиНовойВерсии(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьИзмененияФайлаСРасширениемПослеПроверкиНовойВерсии(ПараметрыВыполнения)
	
	Если Не ПараметрыВыполнения.ДанныеФайла.Зашифрован Тогда
		СохранитьИзмененияФайлаСРасширениемПослеПроверкиЗашифрован(ПараметрыВыполнения);
		Возврат;
	КонецЕсли;
	
	// Файл с признаком шифрован снова шифруется для тех же сертификатов.
	
	ЗашифроватьФайлПередПомещениемВХранилищеФайлов(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИРабочийКаталог
//
Процедура СохранитьИзмененияФайлаСРасширениемПослеПроверкиЗашифрован(ПараметрыВыполнения)
	
	СведенияОФайле = РаботаСФайламиКлиентСервер.СведенияОФайле("ФайлСВерсией", ПараметрыВыполнения.ФайлНовойВерсии);
	СведенияОФайле.Комментарий = ПараметрыВыполнения.КомментарийКВерсии;
	СведенияОФайле.ХранитьВерсии = ПараметрыВыполнения.СоздатьНовуюВерсию;
	
	Если ПараметрыВыполнения.Свойство("АдресПослеШифрования") Тогда
		СведенияОФайле.АдресВременногоХранилищаФайла = ПараметрыВыполнения.АдресПослеШифрования;
	Иначе
		ПомещаемыеФайлы = Новый Массив;
		Описание = Новый ОписаниеПередаваемогоФайла(ПараметрыВыполнения.ПолныйПутьКФайлу, "");
		ПомещаемыеФайлы.Добавить(Описание);
		
		ПомещенныеФайлы = Новый Массив;
		ФайлыПомещены = ПоместитьФайлы(ПомещаемыеФайлы, ПомещенныеФайлы, , Ложь, ПараметрыВыполнения.ИдентификаторФормы);
		
		Если Не ФайлыПомещены Тогда
			ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Истина);
			Возврат;
		КонецЕсли;
		
		Если ПомещенныеФайлы.Количество() = 1 Тогда
			СведенияОФайле.АдресВременногоХранилищаФайла = ПомещенныеФайлы[0].Хранение;
		КонецЕсли;
	КонецЕсли;
	
	ОбщиеНастройкиРаботыСФайлами = ОбщиеНастройкиРаботыСФайлами();
	ИмяКаталога = РабочийКаталогПользователя();
	
	ОтносительныйПутьКФайлу = "";
	Если ПараметрыВыполнения.ДанныеФайла.РабочийКаталогВладельца <> "" Тогда // Есть рабочий каталог.
		ОтносительныйПутьКФайлу = ПараметрыВыполнения.ПолныйПутьКФайлу;
	Иначе
		Позиция = СтрНайти(ПараметрыВыполнения.ПолныйПутьКФайлу, ИмяКаталога);
		Если Позиция <> 0 Тогда
			ОтносительныйПутьКФайлу = Сред(ПараметрыВыполнения.ПолныйПутьКФайлу, СтрДлина(ИмяКаталога) + 1);
		КонецЕсли;
	КонецЕсли;
	
	Если Не ОбщиеНастройкиРаботыСФайлами.ИзвлекатьТекстыФайловНаСервере Тогда
		СведенияОФайле.АдресВременногоХранилищаТекста = ИзвлечьТекстВоВременноеХранилище(ПараметрыВыполнения.ПолныйПутьКФайлу,
			ПараметрыВыполнения.ИдентификаторФормы);
	Иначе
		СведенияОФайле.АдресВременногоХранилищаТекста = "";
	КонецЕсли;
	
	НеМенятьЗаписьВРабочемКаталоге = Ложь;
	Если ПараметрыВыполнения.ПереданныйПолныйПутьКФайлу <> "" Тогда
		НеМенятьЗаписьВРабочемКаталоге = Истина;
	КонецЕсли;
	
	ВерсияОбновлена = РаботаСФайламиСлужебныйВызовСервера.СохранитьИзмененияФайла(ПараметрыВыполнения.ДанныеФайла.Ссылка, СведенияОФайле, 
		НеМенятьЗаписьВРабочемКаталоге, ОтносительныйПутьКФайлу, ПараметрыВыполнения.ПолныйПутьКФайлу, 
		ПараметрыВыполнения.ДанныеФайла.РабочийКаталогВладельца <> "", ПараметрыВыполнения.ИдентификаторФормы);
	Если ПараметрыВыполнения.ПоказыватьОповещение Тогда
		Если ВерсияОбновлена Тогда
			ПоказатьОповещениеПользователя(
				НСтр("ru = 'Новая версия сохранена'"),
				ПараметрыВыполнения.ДанныеФайла.НавигационнаяСсылка,
				ПараметрыВыполнения.ДанныеФайла.ПолноеНаименованиеВерсии,
				БиблиотекаКартинок.Информация32);
		Иначе
			ПоказатьОповещениеПользователя(
				НСтр("ru = 'Новая версия не сохранена'"),,
				НСтр("ru = 'Файл не изменился'"),
				БиблиотекаКартинок.Информация32);
			Обработчик = Новый ОписаниеОповещения("СохранитьИзмененияФайлаСРасширениемПослеПоказаОповещения", ЭтотОбъект, ПараметрыВыполнения);
			ПоказатьИнформациюФайлНеБылИзменен(Обработчик);
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	СохранитьИзмененияФайлаСРасширениемПослеПоказаОповещения(-1, ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьИзмененияФайлаСРасширениемПослеПоказаОповещения(Результат, ПараметрыВыполнения) Экспорт
	
	Если  ТипЗнч(Результат) = Тип("Структура") И Результат.Свойство("БольшеНеЗадаватьЭтотВопрос") И Результат.БольшеНеЗадаватьЭтотВопрос Тогда
		ОбщегоНазначенияВызовСервера.ХранилищеОбщихНастроекСохранить(
			"НастройкиПрограммы","ПоказыватьИнформациюЧтоФайлНеБылИзменен", Ложь,,, Истина);
		ОбновитьПовторноИспользуемыеЗначения();
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Истина);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьИзмененияФайлаБезРасширения(ПараметрыВыполнения)
	
	Если ПараметрыВыполнения.ХранитьВерсии = Неопределено Тогда
		ПараметрыДанныхФайла = РаботаСФайламиКлиентСервер.ПараметрыДанныхФайла();
		ПараметрыДанныхФайла.ПолучатьСсылкуНаДвоичныеДанные = Ложь;
		
		ПараметрыВыполнения.ДанныеФайла = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла(ПараметрыВыполнения.ОбъектСсылка,,ПараметрыДанныхФайла);
		ПараметрыВыполнения.ХранитьВерсии                      = ПараметрыВыполнения.ДанныеФайла.ХранитьВерсии;
		ПараметрыВыполнения.ФайлРедактируетТекущийПользователь = ПараметрыВыполнения.ДанныеФайла.ФайлРедактируетТекущийПользователь;
		ПараметрыВыполнения.Редактирует                        = ПараметрыВыполнения.ДанныеФайла.Редактирует;
		ПараметрыВыполнения.АвторТекущейВерсии                 = ПараметрыВыполнения.ДанныеФайла.АвторТекущейВерсии;
	КонецЕсли;
	
	// Проверка возможности освобождения файла.
	ТекстОшибки = "";
	МожноОсвободитьФайл = ВозможностьОсвободитьФайл(
		ПараметрыВыполнения.ОбъектСсылка,
		ПараметрыВыполнения.ФайлРедактируетТекущийПользователь,
		ПараметрыВыполнения.Редактирует,
		ТекстОшибки);
	Если Не МожноОсвободитьФайл Тогда
		ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, ТекстОшибки, Ложь);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.ПолныйПутьКФайлу = "";
	Если ПараметрыВыполнения.СоздатьНовуюВерсию = Неопределено Тогда
		
		// Запрос комментария и признака хранения версии.
		ПараметрыВыполнения.СоздатьНовуюВерсию = Истина;
		СоздатьНовуюВерсиюДоступность = Истина;
		
		Если ПараметрыВыполнения.ХранитьВерсии Тогда
			ПараметрыВыполнения.СоздатьНовуюВерсию = Истина;
			
			// Если автор текущей версии не текущий пользователь, тогда
			// отключается доступность флажка "Не создавать новую версию".
			Если ПараметрыВыполнения.АвторТекущейВерсии <> ПараметрыВыполнения.Редактирует Тогда
				СоздатьНовуюВерсиюДоступность = Ложь;
			Иначе
				СоздатьНовуюВерсиюДоступность = Истина;
			КонецЕсли;
		Иначе
			ПараметрыВыполнения.СоздатьНовуюВерсию = Ложь;
			СоздатьНовуюВерсиюДоступность = Ложь;
		КонецЕсли;
		
		СтруктураПараметров = Новый Структура;
		СтруктураПараметров.Вставить("ФайлСсылка",                    ПараметрыВыполнения.ОбъектСсылка);
		СтруктураПараметров.Вставить("КомментарийКВерсии",            "");
		СтруктураПараметров.Вставить("СоздатьНовуюВерсию",            ПараметрыВыполнения.СоздатьНовуюВерсию);
		СтруктураПараметров.Вставить("СоздатьНовуюВерсиюДоступность", СоздатьНовуюВерсиюДоступность);
		
		Обработчик = Новый ОписаниеОповещения("СохранитьИзмененияФайлаБезРасширенияПослеПомещенияФайлаНаСервер", ЭтотОбъект, ПараметрыВыполнения);
		
		ОткрытьФорму("Обработка.РаботаСФайлами.Форма.ФормаВозвратаФайла", СтруктураПараметров, , , , , Обработчик);
		
	Иначе // Параметры СоздатьНовуюВерсию и КомментарийКВерсии переданы извне.
		
		Если ПараметрыВыполнения.ХранитьВерсии Тогда
			
			// Если автор текущей версии не текущий пользователь, тогда
			// отключается доступность флажка "Не создавать новую версию".
			Если ПараметрыВыполнения.АвторТекущейВерсии <> ПараметрыВыполнения.Редактирует Тогда
				ПараметрыВыполнения.СоздатьНовуюВерсию = Истина;
			КонецЕсли;
			
		Иначе
			ПараметрыВыполнения.СоздатьНовуюВерсию = Ложь;
		КонецЕсли;
		
		СохранитьИзмененияФайлаБезРасширенияПослеПроверкиНовойВерсии(ПараметрыВыполнения);
		
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьИзмененияФайлаБезРасширенияПослеПомещенияФайлаНаСервер(Результат, ПараметрыВыполнения) Экспорт
	
	Если ТипЗнч(Результат) <> Тип("Структура") Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	Если Результат.КодВозврата <> КодВозвратаДиалога.ОК Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.СоздатьНовуюВерсию = Результат.СоздатьНовуюВерсию;
	ПараметрыВыполнения.КомментарийКВерсии = Результат.КомментарийКВерсии;
	
	СохранитьИзмененияФайлаБезРасширенияПослеПроверкиНовойВерсии(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьИзмененияФайлаБезРасширенияПослеПроверкиНовойВерсии(ПараметрыВыполнения)
	
	Обработчик = Новый ОписаниеОповещения("СохранитьИзмененияФайлаБезРасширенияПослеНапоминания", ЭтотОбъект, ПараметрыВыполнения);
	ПоказатьНапоминаниеПередПоместитьФайл(Обработчик);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьИзмененияФайлаБезРасширенияПослеНапоминания(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат.Значение = КодВозвратаДиалога.ОК Тогда
		
		Если  ТипЗнч(Результат) = Тип("Структура") И Результат.Свойство("БольшеНеЗадаватьЭтотВопрос") И Результат.БольшеНеЗадаватьЭтотВопрос Тогда
			ОбщегоНазначенияВызовСервера.ХранилищеОбщихНастроекСохранить(
				"НастройкиПрограммы", "ПоказыватьПодсказкиПриРедактированииФайлов", Ложь,,, Истина);
		КонецЕсли;
		Обработчик = Новый ОписаниеОповещения("СохранитьИзмененияФайлаБезРасширенияПослеЗагрузкиФайла", ЭтотОбъект, ПараметрыВыполнения);
		НачатьПомещениеФайла(Обработчик, , ПараметрыВыполнения.ПолныйПутьКФайлу, , ПараметрыВыполнения.ИдентификаторФормы);
		
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьИзмененияФайлаБезРасширенияПослеЗагрузкиФайла(Помещен, Адрес, ВыбранноеИмяФайла, ПараметрыВыполнения) Экспорт
	
	Если Не Помещен Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.Вставить("АдресЗагруженногоФайла", Адрес);
	ПараметрыВыполнения.Вставить("ВыбранноеИмяФайла", ВыбранноеИмяФайла);
	
	Если ПараметрыВыполнения.ДанныеФайла = Неопределено Тогда
		ПараметрыДанныхФайла = РаботаСФайламиКлиентСервер.ПараметрыДанныхФайла();
		ПараметрыДанныхФайла.ПолучатьСсылкуНаДвоичныеДанные = Ложь;
		ДанныеФайла = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла(ПараметрыВыполнения.ОбъектСсылка,,ПараметрыДанныхФайла);
	Иначе
		ДанныеФайла = ПараметрыВыполнения.ДанныеФайла;
	КонецЕсли;
	Если Не ДанныеФайла.Зашифрован Тогда
		СохранитьИзмененияФайлаБезРасширенияПослеШифрованияФайла(Null, ПараметрыВыполнения);
		Возврат;
	КонецЕсли;
	Если СертификатыНеУказаны(ДанныеФайла.МассивСертификатовШифрования) Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	// Не нужно ПредложитьУстановкуРасширенияРаботыСФайлами(), т.к. все делается в памяти через ДвоичныеДанные.
	
	ОписаниеДанных = Новый Структура;
	ОписаниеДанных.Вставить("Операция",            НСтр("ru = 'Шифрование файла'"));
	ОписаниеДанных.Вставить("ЗаголовокДанных",     НСтр("ru = 'Файл'"));
	ОписаниеДанных.Вставить("Данные",              Адрес);
	ОписаниеДанных.Вставить("Представление",       ПараметрыВыполнения.ОбъектСсылка);
	ОписаниеДанных.Вставить("НаборСертификатов",   ПараметрыВыполнения.ОбъектСсылка);
	ОписаниеДанных.Вставить("БезПодтверждения",    Истина);
	ОписаниеДанных.Вставить("СообщитьОЗавершении", Ложь);
	
	ОбработчикПродолжения = Новый ОписаниеОповещения("СохранитьИзмененияФайлаБезРасширенияПослеШифрованияФайла",
		ЭтотОбъект, ПараметрыВыполнения);
	
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	МодульЭлектроннаяПодписьКлиент.Зашифровать(ОписаниеДанных, , ОбработчикПродолжения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьИзмененияФайлаБезРасширенияПослеШифрованияФайла(ОписаниеДанных, ПараметрыВыполнения) Экспорт
	
	Если ОписаниеДанных = Null Тогда
		Адрес = ПараметрыВыполнения.АдресЗагруженногоФайла;
		
	ИначеЕсли Не ОписаниеДанных.Успех Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	Иначе
		Если ТипЗнч(ОписаниеДанных.ЗашифрованныеДанные) = Тип("ДвоичныеДанные") Тогда
			Адрес = ПоместитьВоВременноеХранилище(ОписаниеДанных.ЗашифрованныеДанные,
				ПараметрыВыполнения.ИдентификаторФормы);
		Иначе
			Адрес = ОписаниеДанных.ЗашифрованныеДанные;
		КонецЕсли;
	КонецЕсли;
	
	СведенияОФайле = РаботаСФайламиКлиентСервер.СведенияОФайле("ФайлСВерсией");
	ПараметрыВыполнения.АдресВременногоХранилища = Адрес;
	СведенияОФайле.АдресВременногоХранилищаФайла = Адрес;
	СведенияОФайле.ХранитьВерсии = ПараметрыВыполнения.СоздатьНовуюВерсию;
	
	СтруктураПути = ОбщегоНазначенияКлиентСервер.РазложитьПолноеИмяФайла(ПараметрыВыполнения.ВыбранноеИмяФайла);
	Если Не ПустаяСтрока(СтруктураПути.Расширение) Тогда
		СведенияОФайле.РасширениеБезТочки = ОбщегоНазначенияКлиентСервер.РасширениеБезТочки(СтруктураПути.Расширение);
		СведенияОФайле.ИмяБезРасширения = СтруктураПути.ИмяБезРасширения;
	КонецЕсли;
	
	Результат = РаботаСФайламиСлужебныйВызовСервера.ПолучитьДанныеФайлаИСохранитьИзмененияФайла(ПараметрыВыполнения.ОбъектСсылка, СведенияОФайле, 
		"", ПараметрыВыполнения.ПолныйПутьКФайлу, Ложь, ПараметрыВыполнения.ИдентификаторФормы);
	ПараметрыВыполнения.ДанныеФайла = Результат.ДанныеФайла;
	Если ПараметрыВыполнения.ПоказыватьОповещение Тогда
		ПоказатьОповещениеПользователя(
			НСтр("ru = 'Новая версия сохранена'"),
			ПараметрыВыполнения.ДанныеФайла.НавигационнаяСсылка,
			ПараметрыВыполнения.ДанныеФайла.ПолноеНаименованиеВерсии,
			БиблиотекаКартинок.Информация32);
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Истина);
	
КонецПроцедуры


// Для процедур СохранитьИзмененияФайла, ЗакончитьРедактирование.
Процедура ЗашифроватьФайлПередПомещениемВХранилищеФайлов(ПараметрыВыполнения)
	
	Если СертификатыНеУказаны(ПараметрыВыполнения.ДанныеФайла.МассивСертификатовШифрования) Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	// Не нужно ПредложитьУстановкуРасширенияРаботыСФайлами(), т.к. все делается в памяти через ДвоичныеДанные.
	
	ОписаниеДанных = Новый Структура;
	ОписаниеДанных.Вставить("Операция",            НСтр("ru = 'Шифрование файла'"));
	ОписаниеДанных.Вставить("ЗаголовокДанных",     НСтр("ru = 'Файл'"));
	ОписаниеДанных.Вставить("Данные",              ПараметрыВыполнения.ПолныйПутьКФайлу);
	ОписаниеДанных.Вставить("Представление",       ПараметрыВыполнения.ОбъектСсылка);
	ОписаниеДанных.Вставить("НаборСертификатов",   ПараметрыВыполнения.ОбъектСсылка);
	ОписаниеДанных.Вставить("БезПодтверждения",    Истина);
	ОписаниеДанных.Вставить("СообщитьОЗавершении", Ложь);
	
	ОбработчикПродолжения = Новый ОписаниеОповещения("ЗашифроватьФайлПередПомещениемВХранилищеФайловПослеШифрованияФайла",
		ЭтотОбъект, ПараметрыВыполнения);
	
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	МодульЭлектроннаяПодписьКлиент.Зашифровать(ОписаниеДанных, , ОбработчикПродолжения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗашифроватьФайлПередПомещениемВХранилищеФайловПослеШифрованияФайла(ОписаниеДанных, ПараметрыВыполнения) Экспорт
	
	Если ОписаниеДанных = Null Тогда
		Адрес = ПараметрыВыполнения.АдресЗагруженногоФайла;
		
	ИначеЕсли Не ОписаниеДанных.Успех Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	Иначе
		Если ТипЗнч(ОписаниеДанных.ЗашифрованныеДанные) = Тип("ДвоичныеДанные") Тогда
			Адрес = ПоместитьВоВременноеХранилище(ОписаниеДанных.ЗашифрованныеДанные,
				ПараметрыВыполнения.ИдентификаторФормы);
		Иначе
			Адрес = ОписаниеДанных.ЗашифрованныеДанные;
		КонецЕсли;
	КонецЕсли;
	
	ПараметрыВыполнения.Вставить("АдресПослеШифрования", Адрес);
	
	ЗакончитьРедактированиеСРасширениемПослеПроверкиЗашифрован(ПараметрыВыполнения);
	
КонецПроцедуры

// Для процедур СохранитьИзмененияФайла, ЗакончитьРедактирование.
Функция СертификатыНеУказаны(МассивСертификатов)
	
	Если МассивСертификатов.Количество() = 0 Тогда
		ПоказатьПредупреждение(,
			НСтр("ru = 'У зашифрованного файла не указаны сертификаты.
			           |Расшифруйте файл и зашифруйте заново.'"));
		
		Возврат Истина;
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Пометка файла как занятого для редактирования.

// Пометка файла как занятого для редактирования.
//
// Параметры:
//   ОбработчикРезультата - ОписаниеОповещения
//                        - Неопределено - описание процедуры, принимающей результат работы метода.
//   ДанныеФайла - Структура
//
Процедура ЗанятьФайл(ОбработчикРезультата, ДанныеФайла, УникальныйИдентификатор)
	
	ПараметрыОбработчика = Новый Структура;
	ПараметрыОбработчика.Вставить("ОбработчикРезультата",    ОбработчикРезультата);
	ПараметрыОбработчика.Вставить("ДанныеФайла",             ДанныеФайла);
	ПараметрыОбработчика.Вставить("УникальныйИдентификатор", УникальныйИдентификатор);
	
	Обработчик = Новый ОписаниеОповещения("ЗанятьФайлПослеУстановкиРасширения", ЭтотОбъект, ПараметрыОбработчика);
	
	ПоказатьВопросОбУстановкеРасширенияРаботыСФайлами(Обработчик);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   РасширениеУстановлено - Булево
//   ПараметрыВыполнения   - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//
Процедура ЗанятьФайлПослеУстановкиРасширения(РасширениеУстановлено, ПараметрыВыполнения) Экспорт
	
	ТекстОшибки = "";
	МожноЗанятьФайл = РаботаСФайламиКлиентСервер.МожноЛиЗанятьФайл(
		ПараметрыВыполнения.ДанныеФайла,
		ТекстОшибки);
	Если Не МожноЗанятьФайл Тогда
		ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, ТекстОшибки, Неопределено);
		Возврат;
	КонецЕсли;
	
	ТекстОшибки = "";
	
	ПараметрыЗанятияФайла = РаботаСФайламиСлужебныйКлиентСервер.ПараметрыЗанятияФайла();
	ПараметрыЗанятияФайла.УникальныйИдентификатор = ПараметрыВыполнения.УникальныйИдентификатор;
	
	ФайлЗанят = РаботаСФайламиСлужебныйВызовСервера.ЗанятьФайл(ПараметрыВыполнения.ДанныеФайла,
		ТекстОшибки, ПараметрыЗанятияФайла);
	
	Если Не ФайлЗанят Тогда
		ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, ТекстОшибки, Неопределено);
		Возврат;
	КонецЕсли;
	
	Если РасширениеРаботыСФайламиПодключено() Тогда
		НаЧтение = Ложь;
		ВРабочемКаталогеВладельца = ПараметрыВыполнения.ДанныеФайла.РабочийКаталогВладельца <> "";
		ПеререгистрироватьФайлВРабочемКаталоге(ПараметрыВыполнения.ДанныеФайла, НаЧтение, ВРабочемКаталогеВладельца);
	КонецЕсли;
	
	ПоказатьОповещениеПользователя(
		НСтр("ru = 'Редактирование файла'"),
		ПараметрыВыполнения.ДанныеФайла.НавигационнаяСсылка,
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Файл ""%1""
			           |занят для редактирования.'"),
			Строка(ПараметрыВыполнения.ДанныеФайла.Ссылка)),
		БиблиотекаКартинок.Информация32);
	
	ИзменитьКоличествоЗанятыхФайлов(1);
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения.ДанныеФайла);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Добавление файлов.

// Продолжение процедуры ПрисоединенныеФайлыКлиент.ДобавитьФайлы.
Процедура ДобавитьФайлыЗавершение(ПрисоединенныйФайл, ДополнительныеПараметры) Экспорт
	
	Если ПрисоединенныйФайл = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ВладелецФайла = ДополнительныеПараметры.ВладелецФайла;
	ОповеститьОбИзменении(ПрисоединенныйФайл);
	ОповеститьОбИзменении(ВладелецФайла);
	
	ПараметрыОповещения = ПараметрыОповещенияЗаписиФайла();
	ПараметрыОповещения.ВладелецФайла = ВладелецФайла;
	ПараметрыОповещения.Файл = ПрисоединенныйФайл;
	ПараметрыОповещения.ЭтоНовый = Истина;
	Оповестить("Запись_Файл", ПараметрыОповещения, ПрисоединенныйФайл);
	
	Если ДополнительныеПараметры.Свойство("ОбработчикРезультата")
		И ДополнительныеПараметры.ОбработчикРезультата <> Неопределено Тогда
		ПрисоединенныеФайлыМассив = Новый Массив;
		ПрисоединенныеФайлыМассив.Добавить(ПрисоединенныйФайл);
		ВыполнитьОбработкуОповещения(ДополнительныеПараметры.ОбработчикРезультата, ПрисоединенныеФайлыМассив);
	КонецЕсли;
	
	ОткрыватьКарточкуПослеСозданияИзФайла = Ложь;
	Если ДополнительныеПараметры.Свойство("НеОткрыватьКарточкуПослеСозданияИзФайла") Тогда
		ОткрыватьКарточкуПослеСозданияИзФайла = Не ДополнительныеПараметры.НеОткрыватьКарточкуПослеСозданияИзФайла;
	КонецЕсли;
	Если ОткрыватьКарточкуПослеСозданияИзФайла Тогда
		
		ПоказатьОповещениеПользователя(
			НСтр("ru = 'Создание'"),
			ПолучитьНавигационнуюСсылку(ПрисоединенныйФайл),
			ПрисоединенныйФайл,
			БиблиотекаКартинок.Информация32);
		РаботаСФайламиКлиент.ОткрытьФормуФайла(ПрисоединенныйФайл);
			
	КонецЕсли;
		
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Освобождение файлов без обновления.

////////////////////////////////////////////////////////////////////////////////
// Удаление файла. Перед удалением снимается атрибут "Только для чтения".

// Параметры:
//  ПолноеИмяФайла - Строка
//
Процедура УдалитьФайлБезПодтверждения(ПолноеИмяФайла)
	
	Файл = Новый Файл(ПолноеИмяФайла);
	Если Файл.Существует() Тогда
		Попытка
			Файл.УстановитьТолькоЧтение(Ложь);
			УдалитьФайлы(ПолноеИмяФайла);
		Исключение
			ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось удалить файл в рабочем каталоге:
					|""%1"". 
					|Возможно он занят другим приложением.
					|
					|%2'"),
				ПолноеИмяФайла, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
				"Предупреждение", ТекстСообщения,, Истина);
		КонецПопытки;	
	КонецЕсли;
	
КонецПроцедуры

// Удаление файла со снятием атрибута readonly.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Структура
//                       - Неопределено - описание процедуры, принимающей результат
//                         работы метода.
//  ПолноеИмяФайла - Строка -  полное имя файла.
//  ЗадаватьВопрос - Булево- задавать вопрос об удалении.
//  ШапкаВопроса - Строка - шапка вопроса - добавляет текст к вопросу об удалении.
//
Процедура УдалитьФайл(Знач ОбработчикРезультата, ПолноеИмяФайла)
	
	УдалитьФайлБезПодтверждения(ПолноеИмяФайла);
	ВернутьРезультат(ОбработчикРезультата, Истина);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Получение файла из хранилища в рабочий каталог.

// Получает Файл из хранилища файлов в рабочий каталог
// и возвращает путь к этому файлу.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  ДанныеФайла        - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИРабочийКаталог
//  ПолноеИмяФайла     - Строка.
//  НаЧтение           - Булево - Ложь - для чтения, Истина для редактирования.
//  ИдентификаторФормы - УникальныйИдентификатор - идентификатор формы.
//
Процедура ПолучитьФайлВерсииВЛокальныйКэшФайлов(ОбработчикРезультата, ДанныеФайла, НаЧтение,
	ИдентификаторФормы, ДополнительныеПараметры)
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("ДанныеФайла", ДанныеФайла);
	ПараметрыВыполнения.Вставить("НаЧтение", НаЧтение);
	ПараметрыВыполнения.Вставить("ИдентификаторФормы", ИдентификаторФормы);
	ПараметрыВыполнения.Вставить("ДополнительныеПараметры", ДополнительныеПараметры);
	
	ПараметрыВыполнения.Вставить("ПолноеИмяФайла", "");
	ПараметрыВыполнения.Вставить("ФайлПолучен", Ложь);	
	ВРабочемКаталогеНаЧтение = Истина;
	ВРабочемКаталогеВладельца = Ложь;
	
	ФайлВРабочемКаталоге = ФайлНаходитсяВЛокальномКэшеФайлов(ДанныеФайла,
		ДанныеФайла.Версия, ПараметрыВыполнения.ПолноеИмяФайла,
		ВРабочемКаталогеНаЧтение, ВРабочемКаталогеВладельца);
	Если Не ФайлВРабочемКаталоге Тогда
		ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайлов(ПараметрыВыполнения);
		Возврат;
	КонецЕсли;

	// Получаем путь файла в рабочем каталоге - с проверкой на уникальность.
	Если ПараметрыВыполнения.ПолноеИмяФайла = "" Тогда
		ОбщегоНазначенияКлиент.СообщитьПользователю(
			НСтр("ru = 'Не удалось получить файл из программы в рабочий каталог на компьютере.'"));
		ВернутьРезультат(ОбработчикРезультата, ПараметрыВыполнения);
		Возврат;
	КонецЕсли;
	
	// Выяснено, что Файл в рабочем каталоге есть.
	// Проверка даты изменения и принятие решения, что делать дальше.
	Обработчик = Новый ОписаниеОповещения("ПолучитьФайлВерсииВЛокальныйКэшФайловПослеВыбораДействия", 
		ЭтотОбъект, ПараметрыВыполнения);
	ДействиеПриОткрытииФайлаВРабочемКаталоге(Обработчик, ПараметрыВыполнения.ПолноеИмяФайла, ДанныеФайла);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПолучитьФайлВерсииВЛокальныйКэшФайловПослеВыбораДействия(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат = "ВзятьИзХранилищаИОткрыть" Тогда
		
		Обработчик = Новый ОписаниеОповещения("ПолучитьФайлВерсииВЛокальныйКэшФайловПослеУдаления", ЭтотОбъект, ПараметрыВыполнения);
		УдалитьФайл(Обработчик, ПараметрыВыполнения.ПолноеИмяФайла);
		
	ИначеЕсли Результат = "ОткрытьСуществующий" Тогда
		
		Если ПараметрыВыполнения.ДанныеФайла.ВРабочемКаталогеНаЧтение <> ПараметрыВыполнения.НаЧтение Тогда
			ВРабочемКаталогеВладельца = ПараметрыВыполнения.ДанныеФайла.РабочийКаталогВладельца <> "";
			
			ПеререгистрироватьВРабочемКаталоге(
				ПараметрыВыполнения.ДанныеФайла.Версия,
				ПараметрыВыполнения.ПолноеИмяФайла,
				ПараметрыВыполнения.НаЧтение,
				ВРабочемКаталогеВладельца);
		КонецЕсли;
		
		ПараметрыВыполнения.ФайлПолучен = Истина;
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
		
	Иначе // Результат = "Отмена".
		ПараметрыВыполнения.ПолноеИмяФайла = "";
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
Процедура ПолучитьФайлВерсииВЛокальныйКэшФайловПослеУдаления(ФайлУдален, ПараметрыВыполнения) Экспорт
	
	ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайлов(ПараметрыВыполнения);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Получение файла из программы на компьютер.

// Получить файл из программы на компьютер и возвращает путь к этому файлу.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы процедуры.
//  ДанныеФайла  - Структура
//  ПолноеИмяФайла - Строка - здесь возвращается полное имя файла.
//  ИдентификаторФормы - УникальныйИдентификатор - идентификатор формы.
//
Процедура ПолучитьФайлВерсииВРабочийКаталог(ОбработчикРезультата, ДанныеФайла, ПолноеИмяФайла,
	ИдентификаторФормы = Неопределено, ДополнительныеПараметры = Неопределено) Экспорт
	
	ИмяКаталога = РабочийКаталогПользователя();	
	Если ИмяКаталога = Неопределено Или ПустаяСтрока(ИмяКаталога) Тогда
		ВернутьРезультат(ОбработчикРезультата, Новый Структура("ФайлПолучен, ПолноеИмяФайла", Ложь, ПолноеИмяФайла));
		Возврат;
	КонецЕсли;
	
	Если ДанныеФайла.РабочийКаталогВладельца = "" 
		Или ДанныеФайла.Версия <> ДанныеФайла.ТекущаяВерсия И ЗначениеЗаполнено(ДанныеФайла.ТекущаяВерсия) Тогда
		ПолучитьФайлВерсииВЛокальныйКэшФайлов(ОбработчикРезультата, ДанныеФайла, ДанныеФайла.НаЧтение,
			ИдентификаторФормы, ДополнительныеПараметры);
	Иначе
		
		Если Не РабочийКаталогДоступен(ДанныеФайла.РабочийКаталогВладельца, ДанныеФайла.Владелец) Тогда
			ПолучитьФайлВерсииВЛокальныйКэшФайлов(ОбработчикРезультата, ДанныеФайла, ДанныеФайла.НаЧтение,
			ИдентификаторФормы, ДополнительныеПараметры);
			Возврат;
		КонецЕсли;
			
		ПолучитьФайлВерсииВРабочийКаталогПапки(ОбработчикРезультата, ДанныеФайла, ПолноеИмяФайла, ДанныеФайла.НаЧтение,
			ИдентификаторФормы, ДополнительныеПараметры);
	КонецЕсли;
	
КонецПроцедуры

Функция РабочийКаталогДоступен(РабочийКаталогВладельца, Владелец)
	Результат = Ложь;
	// Создать каталог для файлов.
	Попытка
		// В случае если передан каталог, имя которого запрещено в текущей файловой системе,
		// исключение вызвано не будет, хотя каталог будет не доступен.
		СведенияОКаталоге = Новый Файл(РабочийКаталогВладельца);
		Если НЕ СведенияОКаталоге.Существует() Тогда
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru='Каталог папки файлов %1 не существует.'"), 
				Владелец);
		КонецЕсли;
		СоздатьКаталог(РабочийКаталогВладельца);
		ИмяКаталогаТестовое = РабочийКаталогВладельца + "ПроверкаДоступа\";
		СоздатьКаталог(ИмяКаталогаТестовое);
		УдалитьФайлы(ИмяКаталогаТестовое);
		Результат = Истина;
	Исключение
		// Нет прав на создание каталога, или такой путь отсутствует,
		// тогда установка настроек по умолчанию.
		СообщениеЖурналаРегистрации = НСтр("ru='Не найден рабочий каталог %1 для папки файлов %2 или нет права на запись. Восстановлены настройки по умолчанию.'");
		СообщениеЖурналаРегистрации = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СообщениеЖурналаРегистрации, 
			РабочийКаталогВладельца, Владелец);
		РабочийКаталогВладельца = "";
		
		РаботаСФайламиСлужебныйВызовСервера.ОчиститьРабочийКаталог(Владелец);
		
		ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(
			НСтр("ru='Работа с файлами'", ОбщегоНазначенияКлиент.КодОсновногоЯзыка()),
			"Предупреждение",
			СообщениеЖурналаРегистрации,
			ОбщегоНазначенияКлиент.ДатаСеанса(),
			Истина);
	КонецПопытки;
	Возврат Результат;
КонецФункции

// См. одноименную процедуру в общем модуле РаботаСФайламиКлиент.
Процедура ПолучитьПрисоединенныйФайл(Оповещение, ПрисоединенныйФайл, ИдентификаторФормы, ДополнительныеПараметры = Неопределено) Экспорт
	
	Если ДополнительныеПараметры = Неопределено Тогда
		ДополнительныеПараметры = Новый Структура;
	КонецЕсли;
	
	ДополнительныеПараметрыПоУмолчанию = Новый Структура;
	ДополнительныеПараметрыПоУмолчанию.Вставить("ДляРедактирования", Ложь);
	ДополнительныеПараметрыПоУмолчанию.Вставить("ДанныеФайла",       Неопределено);
	ЗаполнитьЗначенияСвойств(ДополнительныеПараметрыПоУмолчанию, ДополнительныеПараметры);
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение",         Оповещение);
	Контекст.Вставить("ПрисоединенныйФайл", ПрисоединенныйФайл);
	Контекст.Вставить("ИдентификаторФормы", ИдентификаторФормы);
	
	ОбщегоНазначенияКлиентСервер.ДополнитьСтруктуру(Контекст, ДополнительныеПараметрыПоУмолчанию);
	
	Если ТипЗнч(Контекст.ДанныеФайла) <> Тип("Структура")
		Или Не ЗначениеЗаполнено(Контекст.ДанныеФайла.СсылкаНаДвоичныеДанныеФайла) Тогда
		
		Контекст.Вставить("ДанныеФайла", РаботаСФайламиСлужебныйВызовСервера.ПолучитьДанныеФайла(
			Контекст.ПрисоединенныйФайл, Контекст.ИдентификаторФормы, Истина, Контекст.ДляРедактирования));
	КонецЕсли;
	
	Контекст.Вставить("ЗаголовокОшибки",
		НСтр("ru = 'Не удалось получить файл на компьютер из программы по причине:'") + Символы.ПС);
	
	Если Контекст.ДляРедактирования
	   И Контекст.ДанныеФайла.Редактирует <> ПользователиКлиент.АвторизованныйПользователь() Тогда
		
		Результат = Новый Структура;
		Результат.Вставить("ПолноеИмяФайла", "");
		Результат.Вставить("ОписаниеОшибки", Контекст.ЗаголовокОшибки 
			+ СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Файл уже редактирует %1.'"), Строка(Контекст.ДанныеФайла.Редактирует)));
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
		Возврат;
	КонецЕсли;
	
	Контекст.Вставить("ДляРедактирования", ЗначениеЗаполнено(Контекст.ДанныеФайла.Редактирует));
	ФайловаяСистемаКлиент.ПодключитьРасширениеДляРаботыСФайлами(Новый ОписаниеОповещения(
		"ПолучитьПрисоединенныйФайлПослеПодключенияРасширения", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры ПолучитьПрисоединенныйФайл.
Процедура ПолучитьПрисоединенныйФайлПослеПодключенияРасширения(РасширениеПодключено, Контекст) Экспорт
	
	Если Не РасширениеПодключено Тогда
		Результат = Новый Структура;
		Результат.Вставить("ПолноеИмяФайла", "");
		Результат.Вставить("ОписаниеОшибки", Контекст.ЗаголовокОшибки
			+ НСтр("ru = 'Не установлено расширение для работы с 1С:Предприятием.'"));
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
		Возврат;
	КонецЕсли;
	
	ПолучитьРабочийКаталогПользователя(Новый ОписаниеОповещения(
		"ПолучитьПрисоединенныйФайлПослеПолученияРабочегоКаталога", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры ПолучитьПрисоединенныйФайл.
Процедура ПолучитьПрисоединенныйФайлПослеПолученияРабочегоКаталога(Результат, Контекст) Экспорт
	
	Если ЗначениеЗаполнено(Результат.ОписаниеОшибки) Тогда
		Результат = Новый Структура;
		Результат.Вставить("ПолноеИмяФайла", "");
		Результат.Вставить("ОписаниеОшибки", Контекст.ЗаголовокОшибки + Результат.ОписаниеОшибки);
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
		Возврат;
	КонецЕсли;
	
	Контекст.Вставить("РабочийКаталогПользователя", Результат.Каталог);
	Контекст.Вставить("КаталогФайла", Контекст.РабочийКаталогПользователя + Контекст.ДанныеФайла.ОтносительныйПуть);
	Контекст.Вставить("ПолноеИмяФайла", Контекст.КаталогФайла + Контекст.ДанныеФайла.ИмяФайла);
	
	ДействияСФайлом = Новый Массив;
	
	Действие = Новый Структура;
	Действие.Вставить("Действие", "СоздатьКаталог");
	Действие.Вставить("Файл", Контекст.КаталогФайла);
	Действие.Вставить("ЗаголовокОшибки", Контекст.ЗаголовокОшибки
		+ НСтр("ru = 'Создание каталога не выполнено по причине:'"));
	ДействияСФайлом.Добавить(Действие);
	
	Действие = Новый Структура;
	Действие.Вставить("Действие", "УстановитьСвойства");
	Действие.Вставить("Файл",  Контекст.ПолноеИмяФайла);
	Действие.Вставить("Свойства", Новый Структура("ТолькоЧтение", Ложь));
	Действие.Вставить("ЗаголовокОшибки", Контекст.ЗаголовокОшибки
		+ НСтр("ru = 'Изменение свойства файла ""Только просмотр"" не выполнено по причине:'"));
	ДействияСФайлом.Добавить(Действие);
	
	Действие = Новый Структура;
	Действие.Вставить("Действие", "Получить");
	Действие.Вставить("Файл",  Контекст.ПолноеИмяФайла);
	Действие.Вставить("Адрес", Контекст.ДанныеФайла.СсылкаНаДвоичныеДанныеФайла);
	Действие.Вставить("ЗаголовокОшибки", Контекст.ЗаголовокОшибки);
	ДействияСФайлом.Добавить(Действие);
	
	СвойстваФайла = Новый Структура;
	СвойстваФайла.Вставить("ТолькоЧтение", Не Контекст.ДляРедактирования);
	СвойстваФайла.Вставить("УниверсальноеВремяИзменения", Контекст.ДанныеФайла.ДатаМодификацииУниверсальная);
	
	Действие = Новый Структура;
	Действие.Вставить("Действие", "УстановитьСвойства");
	Действие.Вставить("Файл",  Контекст.ПолноеИмяФайла);
	Действие.Вставить("Свойства", СвойстваФайла);
	Действие.Вставить("ЗаголовокОшибки", Контекст.ЗаголовокОшибки
		+ НСтр("ru = 'Установка свойств файла не выполнена по причине:'"));
	ДействияСФайлом.Добавить(Действие);
	
	ОбработатьФайл(Новый ОписаниеОповещения(
			"ПолучитьПрисоединенныйФайлПослеОбработкиФайла", ЭтотОбъект, Контекст),
		ДействияСФайлом, Контекст.ИдентификаторФормы);
	
КонецПроцедуры

// Продолжение процедуры ПолучитьПрисоединенныйФайл.
Процедура ПолучитьПрисоединенныйФайлПослеОбработкиФайла(РезультатДействий, Контекст) Экспорт
	
	Результат = Новый Структура;
	
	Если ЗначениеЗаполнено(РезультатДействий.ОписаниеОшибки) Тогда
		Результат.Вставить("ПолноеИмяФайла", "");
		Результат.Вставить("ОписаниеОшибки", РезультатДействий.ОписаниеОшибки);
	Иначе
		Результат.Вставить("ПолноеИмяФайла", Контекст.ПолноеИмяФайла);
		Результат.Вставить("ОписаниеОшибки", "");
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
	
КонецПроцедуры

// См. одноименную процедуру в общем модуле ПрисоединенныеФайлыКлиент.
Процедура ПоместитьПрисоединенныйФайл(Оповещение, ПрисоединенныйФайл, ИдентификаторФормы, ДополнительныеПараметры = Неопределено) Экспорт
	
	Если ДополнительныеПараметры = Неопределено Тогда
		ДополнительныеПараметры = Новый Структура;
	КонецЕсли;
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение",                Оповещение);
	Контекст.Вставить("ПрисоединенныйФайл",        ПрисоединенныйФайл);
	Контекст.Вставить("ИдентификаторФормы",        ИдентификаторФормы);
	Контекст.Вставить("ДанныеФайла",               Неопределено);
	Контекст.Вставить("ПолноеИмяПомещаемогоФайла", Неопределено);
	ДополнительныеПараметры.Свойство("ДанныеФайла",    Контекст.ДанныеФайла);
	ДополнительныеПараметры.Свойство("ПолноеИмяФайла", Контекст.ПолноеИмяПомещаемогоФайла);
	
	Если ТипЗнч(Контекст.ДанныеФайла) <> Тип("Структура") Тогда
		Контекст.Вставить("ДанныеФайла", РаботаСФайламиСлужебныйВызовСервера.ПолучитьДанныеФайла(
			Контекст.ПрисоединенныйФайл, Контекст.ИдентификаторФормы, Ложь));
	КонецЕсли;
	
	Контекст.Вставить("ЗаголовокОшибки",
		НСтр("ru = 'Не удалось поместить файл с компьютера в программу по причине:'") + Символы.ПС);
	
	ФайловаяСистемаКлиент.ПодключитьРасширениеДляРаботыСФайлами(Новый ОписаниеОповещения(
		"ПоместитьПрисоединенныйФайлПослеПодключенияРасширения", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры ПоместитьПрисоединенныйФайл.
Процедура ПоместитьПрисоединенныйФайлПослеПодключенияРасширения(РасширениеПодключено, Контекст) Экспорт
	
	Если Не РасширениеПодключено Тогда
		Результат = Новый Структура;
		Результат.Вставить("ОписаниеОшибки", Контекст.ЗаголовокОшибки
			+ НСтр("ru = 'Не установлено расширение для работы с 1С:Предприятием.'"));
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
		Возврат;
	КонецЕсли;
	
	ПолучитьРабочийКаталогПользователя(Новый ОписаниеОповещения(
		"ПоместитьПрисоединенныйФайлПослеПолученияРабочегоКаталога", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры ПоместитьПрисоединенныйФайл.
Процедура ПоместитьПрисоединенныйФайлПослеПолученияРабочегоКаталога(Результат, Контекст) Экспорт
	
	Если ЗначениеЗаполнено(Результат.ОписаниеОшибки) Тогда
		ОшибочныйРезультат = Новый Структура;
		ОшибочныйРезультат.Вставить("ОписаниеОшибки", Контекст.ЗаголовокОшибки + Результат.ОписаниеОшибки);
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, ОшибочныйРезультат);
		Возврат;
	КонецЕсли;
	
	Контекст.Вставить("РабочийКаталогПользователя", Результат.Каталог);
	Контекст.Вставить("КаталогФайла",   Контекст.РабочийКаталогПользователя + Контекст.ДанныеФайла.ОтносительныйПуть);
	Контекст.Вставить("ПолноеИмяФайла", Контекст.КаталогФайла + Контекст.ДанныеФайла.ИмяФайла);
	
	Файл = Новый Файл(Контекст.ПолноеИмяФайла);
	
	Файл.НачатьПроверкуСуществования(Новый ОписаниеОповещения(
		"ПоместитьПрисоединенныйФайлПослеПолученияРабочегоКаталогаПродолжение",
		ЭтотОбъект,
		Контекст));
	
КонецПроцедуры

Процедура ПоместитьПрисоединенныйФайлПослеПолученияРабочегоКаталогаПродолжение(ФайлСуществует, Контекст) Экспорт
	Если НЕ ФайлСуществует Тогда
		// для совместимости двух подсистем.
		Контекст.Вставить("КаталогФайла",   Контекст.РабочийКаталогПользователя);
		Контекст.Вставить("ПолноеИмяФайла", Контекст.ДанныеФайла.ПолноеИмяФайлаВРабочемКаталоге);
		
		Если ПустаяСтрока(Контекст.ДанныеФайла.ПолноеИмяФайлаВРабочемКаталоге) Тогда
			// файла нет в рабочем каталоге, просто освобождаем его.
			ОсвободитьФайлБезВопроса(Контекст.ДанныеФайла, Контекст.ИдентификаторФормы);
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(Контекст.ПолноеИмяПомещаемогоФайла) Тогда
		Контекст.ПолноеИмяПомещаемогоФайла = Контекст.ПолноеИмяФайла;
	КонецЕсли;
	
	ОписаниеФайла = Новый ОписаниеПередаваемогоФайла(Контекст.ПолноеИмяФайла);
	ПомещаемыеФайлы = Новый Массив;
	ПомещаемыеФайлы.Добавить(ОписаниеФайла);
	
	ДействияСФайлом = Новый Массив;
	
	Вызовы = Новый Массив;
	
	Если Контекст.ПолноеИмяФайла <> Контекст.ПолноеИмяПомещаемогоФайла Тогда
		Действие = Новый Структура;
		Действие.Вставить("Действие", "СоздатьКаталог");
		Действие.Вставить("Файл", Контекст.КаталогФайла);
		Действие.Вставить("ЗаголовокОшибки", Контекст.ЗаголовокОшибки
			+ НСтр("ru = 'Создание каталога не выполнено по причине:'"));
		ДействияСФайлом.Добавить(Действие);
		
		Действие = Новый Структура;
		Действие.Вставить("Действие", "УстановитьСвойства");
		Действие.Вставить("Файл",  Контекст.ПолноеИмяФайла);
		Действие.Вставить("Свойства", Новый Структура("ТолькоЧтение", Ложь));
		Действие.Вставить("ЗаголовокОшибки", Контекст.ЗаголовокОшибки
			+ НСтр("ru = 'Изменение свойства файла ""Только просмотр"" не выполнено по причине:'"));
		ДействияСФайлом.Добавить(Действие);
		
		Действие = Новый Структура;
		Действие.Вставить("Действие", "СкопироватьИзИсточника");
		Действие.Вставить("Файл",     Контекст.ПолноеИмяФайла);
		Действие.Вставить("Источник", Контекст.ПолноеИмяПомещаемогоФайла);
		Действие.Вставить("ЗаголовокОшибки", Контекст.ЗаголовокОшибки
			+ НСтр("ru = 'Копирование файла не выполнено по причине:'"));
		ДействияСФайлом.Добавить(Действие);
		ДобавитьВызов(Вызовы, "НачатьКопированиеФайла", Контекст.ПолноеИмяПомещаемогоФайла, Контекст.ПолноеИмяФайла, Неопределено, Неопределено);
	КонецЕсли;
	
	Действие = Новый Структура;
	Действие.Вставить("Действие", "УстановитьСвойства");
	Действие.Вставить("Файл",  Контекст.ПолноеИмяФайла);
	Действие.Вставить("Свойства", Новый Структура("ТолькоЧтение", Истина));
	Действие.Вставить("ЗаголовокОшибки", Контекст.ЗаголовокОшибки
		+ НСтр("ru = 'Изменение свойства файла ""Только просмотр"" не выполнено по причине:'"));
	ДействияСФайлом.Добавить(Действие);
	
	Контекст.Вставить("СвойстваФайла", Новый Структура);
	Контекст.СвойстваФайла.Вставить("УниверсальноеВремяИзменения");
	Контекст.СвойстваФайла.Вставить("ИмяБезРасширения");
	Контекст.СвойстваФайла.Вставить("Расширение");
	
	Действие = Новый Структура;
	Действие.Вставить("Действие", "ПолучитьСвойства");
	Действие.Вставить("Файл",  Контекст.ПолноеИмяФайла);
	Действие.Вставить("Свойства", Контекст.СвойстваФайла);
	Действие.Вставить("ЗаголовокОшибки", Контекст.ЗаголовокОшибки
		+ НСтр("ru = 'Получение свойств файла не выполнено по причине:'"));
	ДействияСФайлом.Добавить(Действие);
	
	Контекст.Вставить("ДействиеПомещения", Новый Структура);
	Контекст.ДействиеПомещения.Вставить("Действие", "Поместить");
	Контекст.ДействиеПомещения.Вставить("Файл",  Контекст.ПолноеИмяФайла);
	Контекст.ДействиеПомещения.Вставить("ЗаголовокОшибки", Контекст.ЗаголовокОшибки);
	ДействияСФайлом.Добавить(Контекст.ДействиеПомещения);
	ДобавитьВызов(Вызовы, "НачатьПомещениеФайлов", ПомещаемыеФайлы, Неопределено, Ложь, Контекст.ИдентификаторФормы);
	
	Контекст.Вставить("ДействияСФайлом", ДействияСФайлом);
	
	НачатьЗапросРазрешенияПользователя(Новый ОписаниеОповещения(
		"ПоместитьПрисоединенныйФайлПослеПолученияРазрешений", ЭтотОбъект, Контекст), Вызовы);
КонецПроцедуры

Процедура ДобавитьВызов(Вызовы, Метод, П1, П2, П3, П4)
	
	Вызов = Новый Массив;
	Вызов.Добавить(Метод);
	Вызов.Добавить(П1);
	Вызов.Добавить(П2);
	Вызов.Добавить(П3);
	Вызов.Добавить(П4);
	
	Вызовы.Добавить(Вызов);
	
КонецПроцедуры

// Продолжение процедуры ПоместитьПрисоединенныйФайл.
Процедура ПоместитьПрисоединенныйФайлПослеПолученияРазрешений(РазрешенияПолучены, Контекст) Экспорт
	
	Если РазрешенияПолучены Тогда
		ОбработатьФайл(Новый ОписаниеОповещения(
				"ПоместитьПрисоединенныйФайлПослеОбработкиФайла", ЭтотОбъект, Контекст),
			Контекст.ДействияСФайлом, Контекст.ИдентификаторФормы);
	КонецЕсли;
		
КонецПроцедуры

// Продолжение процедуры ПоместитьПрисоединенныйФайл.
Процедура ПоместитьПрисоединенныйФайлПослеОбработкиФайла(РезультатДействий, Контекст) Экспорт
	
	Результат = Новый Структура;
	
	Если ЗначениеЗаполнено(РезультатДействий.ОписаниеОшибки) Тогда
		Результат.Вставить("ОписаниеОшибки", РезультатДействий.ОписаниеОшибки);
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
		Возврат;
	КонецЕсли;
	
	Результат.Вставить("ОписаниеОшибки", "");
	
	Расширение = Контекст.СвойстваФайла.Расширение;
	
	ИнформацияОФайле = Новый Структура;
	ИнформацияОФайле.Вставить("ДатаМодификацииУниверсальная",   Контекст.СвойстваФайла.УниверсальноеВремяИзменения);
	ИнформацияОФайле.Вставить("АдресФайлаВоВременномХранилище", Контекст.ДействиеПомещения.Адрес);
	ИнформацияОФайле.Вставить("АдресВременногоХранилищаТекста", "");
	ИнформацияОФайле.Вставить("ИмяБезРасширения",               Контекст.СвойстваФайла.ИмяБезРасширения);
	ИнформацияОФайле.Вставить("Расширение",                     Прав(Расширение, СтрДлина(Расширение)-1));
	ИнформацияОФайле.Вставить("Редактирует",                    Неопределено);
	
	Попытка
		РаботаСФайламиСлужебныйВызовСервера.ОбновитьПрисоединенныйФайл(
			Контекст.ПрисоединенныйФайл, ИнформацияОФайле);
	Исключение
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		Результат.Вставить("ОписаниеОшибки", Контекст.ЗаголовокОшибки + Символы.ПС
			+ ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
	КонецПопытки;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Результат);
	
КонецПроцедуры

///////////////////////////////////////////////////////////////////////////////
// Открытие проводника с позиционированием на файле.

// Процедура открывает проводник Windows, позиционируясь на Файл.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  ДанныеФайла          - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//
Процедура КаталогФайла(ОбработчикРезультата, ДанныеФайла) Экспорт
	
	// Если Файл без файла  - эта операция не имеет смысла.
	Если ДанныеФайла.Версия.Пустая() Тогда 
		Возврат;
	КонецЕсли;
	
	#Если ВебКлиент Тогда
		Если НЕ РасширениеРаботыСФайламиПодключено() Тогда
			ПоказатьПредупреждениеОНеобходимостиРасширенияРаботыСФайлами(ОбработчикРезультата);
			Возврат;
		КонецЕсли;
	#КонецЕсли
	
	ПолноеИмяФайла = ПолучитьПутьФайлаВРабочемКаталоге(ДанныеФайла);
	Если ОткрытьПроводникСФайлом(ПолноеИмяФайла) Тогда
		Возврат;
	КонецЕсли;
	
	ИмяФайла = ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(
		ДанныеФайла.ПолноеНаименованиеВерсии, ДанныеФайла.Расширение);
	
	ПараметрыОбработчика = Новый Структура;
	ПараметрыОбработчика.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыОбработчика.Вставить("ДанныеФайла", ДанныеФайла);
	ПараметрыОбработчика.Вставить("ИмяФайла", ИмяФайла);
	ПараметрыОбработчика.Вставить("ПолноеИмяФайла", ПолноеИмяФайла);
	Обработчик = Новый ОписаниеОповещения("КаталогФайлаПослеОтветаНаВопросПолучитьФайл", ЭтотОбъект, ПараметрыОбработчика);
	
	КнопкиВопроса = Новый СписокЗначений;
	КнопкиВопроса.Добавить(КодВозвратаДиалога.Да, НСтр("ru = 'Сохранить и открыть каталог'"));
	КнопкиВопроса.Добавить(КодВозвратаДиалога.Нет, НСтр("ru = 'Отмена'"));
	ПоказатьВопрос(Обработчик,
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Каталог файла не существует. Возможно, на данном компьютере файл ""%1"" еще не открывался.
			|Сохранить файл на компьютер и открыть его каталог?'"),
			ИмяФайла),
		КнопкиВопроса);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура КаталогФайлаПослеОтветаНаВопросПолучитьФайл(Ответ, ПараметрыВыполнения) Экспорт
	
	Если Ответ = КодВозвратаДиалога.Да Тогда
		Обработчик = Новый ОписаниеОповещения("КаталогФайлаПослеПолученияФайлаВРабочийКаталог", ЭтотОбъект, ПараметрыВыполнения);
		ПолучитьФайлВерсииВРабочийКаталог(Обработчик, ПараметрыВыполнения.ДанныеФайла, ПараметрыВыполнения.ПолноеИмяФайла);
	Иначе
		КаталогФайлаПослеПолученияФайлаВРабочийКаталог(-1, ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура КаталогФайлаПослеПолученияФайлаВРабочийКаталог(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат <> -1 Тогда
		ПараметрыВыполнения.ПолноеИмяФайла = Результат.ПолноеИмяФайла;
		ОткрытьПроводникСФайлом(ПараметрыВыполнения.ПолноеИмяФайла);
	КонецЕсли;
	
	// Для варианта с хранением файлов в томах удаляем Файл из временного хранилища после получения.
	Если ЭтоАдресВременногоХранилища(ПараметрыВыполнения.ДанныеФайла.НавигационнаяСсылкаТекущейВерсии) Тогда
		УдалитьИзВременногоХранилища(ПараметрыВыполнения.ДанныеФайла.НавигационнаяСсылкаТекущейВерсии);
	КонецЕсли;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Удаление файла с компьютера и из регистра сведений.

// Удалить с компьютера и из регистра сведений.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  Ссылка  - СправочникСсылка.Файлы - файл.
//  УдалитьВРабочемКаталоге - Булево - удалить даже в рабочем каталоге.
//
Процедура УдалитьФайлИзРабочегоКаталога(ОбработчикРезультата, Ссылка, УдалитьВРабочемКаталоге = Ложь)
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("Ссылка", Ссылка);
	ПараметрыВыполнения.Вставить("Успех", Ложь);
	ПараметрыВыполнения.Вставить("ИмяКаталога", РабочийКаталогПользователя());
	
	ПараметрыВыполнения.Вставить("ПолноеИмяФайлаИзРегистра", Неопределено);
	
	ВРабочемКаталогеВладельца = Ложь;
	ПараметрыВыполнения.ПолноеИмяФайлаИзРегистра = РаботаСФайламиСлужебныйВызовСервера.ПолноеИмяФайлаВРабочемКаталоге(
		ПараметрыВыполнения.Ссылка, ПараметрыВыполнения.ИмяКаталога, Ложь, ВРабочемКаталогеВладельца);
	
	Если ПараметрыВыполнения.ПолноеИмяФайлаИзРегистра <> "" Тогда
		
		// Обычно в рабочем каталоге не удаляем - только если передан УдалитьВРабочемКаталоге.
		Если Не ВРабочемКаталогеВладельца ИЛИ УдалитьВРабочемКаталоге = Истина Тогда
			
			ФайлНаДиске = Новый Файл(ПараметрыВыполнения.ПолноеИмяФайлаИзРегистра);
			
			Если ФайлНаДиске.Существует() Тогда
				ФайлНаДиске.УстановитьТолькоЧтение(Ложь);
				
				ОбработчикЗавершения = Новый ОписаниеОповещения("УдалитьФайлИзРабочегоКаталогаПослеУдаленияФайла", ЭтотОбъект);
				ЗарегистрироватьОбработчикЗавершения(ПараметрыВыполнения, ОбработчикЗавершения);
				
				УдалитьФайл(ПараметрыВыполнения, ПараметрыВыполнения.ПолноеИмяФайлаИзРегистра);
				Если ПараметрыВыполнения.АсинхронныйДиалог.Открыт = Истина Тогда
					Возврат;
				КонецЕсли;
				
				УдалитьФайлИзРабочегоКаталогаПослеУдаленияФайла(
					ПараметрыВыполнения.АсинхронныйДиалог.РезультатКогдаНеОткрыт, ПараметрыВыполнения);
				Возврат;
				
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	УдалитьФайлИзРабочегоКаталогаЗавершение(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура УдалитьФайлИзРабочегоКаталогаПослеУдаленияФайла(Результат, ПараметрыВыполнения) Экспорт
	
	ПутьСПодкаталогом = ПараметрыВыполнения.ИмяКаталога;
	Позиция = СтрНайти(ПараметрыВыполнения.ПолноеИмяФайлаИзРегистра, ПолучитьРазделительПути());
	Если Позиция <> 0 Тогда
		ПутьСПодкаталогом = ПутьСПодкаталогом + Лев(ПараметрыВыполнения.ПолноеИмяФайлаИзРегистра, Позиция);
	КонецЕсли;
	
	МассивФайловВКаталоге = НайтиФайлы(ПутьСПодкаталогом, "*");
	Если МассивФайловВКаталоге.Количество() = 0 Тогда
		Если ПутьСПодкаталогом <> ПараметрыВыполнения.ИмяКаталога Тогда
			Попытка
				УдалитьФайлы(ПутьСПодкаталогом);
			Исключение
				ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
					"Предупреждение", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()),, Истина);
			КонецПопытки;	
		КонецЕсли;
	КонецЕсли;
	
	УдалитьФайлИзРабочегоКаталогаЗавершение(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура УдалитьФайлИзРабочегоКаталогаЗавершение(ПараметрыВыполнения)
	
	Если ПараметрыВыполнения.ПолноеИмяФайлаИзРегистра = "" Тогда
		РаботаСФайламиСлужебныйВызовСервера.УдалитьИзРегистра(ПараметрыВыполнения.Ссылка);
	Иначе
		ФайлНаДиске = Новый Файл(ПараметрыВыполнения.ПолноеИмяФайлаИзРегистра);
		Если НЕ ФайлНаДиске.Существует() Тогда
			РаботаСФайламиСлужебныйВызовСервера.УдалитьИзРегистра(ПараметрыВыполнения.Ссылка);
		КонецЕсли;
	КонецЕсли;
	
	ПараметрыВыполнения.Успех = Истина;
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Очистка рабочего каталога.

// Освободить место для помещения файла - если место есть, ничего не делает.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  РеквизитыВерсии  - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//
Процедура ОсвободитьМестоВРабочемКаталоге(ОбработчикРезультата, РеквизитыВерсии)

#Если ВебКлиент Тогда
	// В веб-клиенте нельзя определить количество свободного места на диске.
	ВернутьРезультатПослеПоказаПредупреждения(
		ОбработчикРезультата,
		НСтр("ru = 'Очистка рабочего каталога возможна только в тонком клиенте.'"),
		Неопределено);
	Возврат;
#КонецЕсли
	
	МаксРазмер = ПерсональныеНастройкиРаботыСФайлами().МаксимальныйРазмерЛокальногоКэшаФайлов;
	
	// Если размер РабочийКаталог установлен равным 0,
	// то считается, что никакого ограничения нет и умолчание в 10 Мб не используется.
	Если МаксРазмер = 0 Тогда
		Возврат;
	КонецЕсли;
	
	ИмяКаталога = РабочийКаталогПользователя();
	
	МассивФайлов = НайтиФайлы(ИмяКаталога, ПолучитьМаскуВсеФайлы());
	
	РазмерФайловВРабочемКаталоге = 0;
	КоличествоСуммарное = 0;
	// Вычисление полного размера файлов в рабочем каталоге.
	ОбходФайловРазмер(ИмяКаталога, МассивФайлов, РазмерФайловВРабочемКаталоге, КоличествоСуммарное);
	
	Размер = РеквизитыВерсии.Размер;
	Если РазмерФайловВРабочемКаталоге + Размер > МаксРазмер Тогда
		ОчиститьРабочийКаталог(ОбработчикРезультата, РазмерФайловВРабочемКаталоге, Размер, Ложь); // ОчищатьВсе = Ложь.
	КонецЕсли;
	
КонецПроцедуры

// Очистка рабочего каталога - для освобождения места - в первую очередь удаляет файлы 
// наиболее давно помещенные в рабочий каталог.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  РазмерФайловВРабочемКаталоге  - Число - размер файлов в рабочем каталоге.
//  РазмерДобавляемогоФайла - Число - размер добавляемого файла.
//  ОчищатьВсе - Булево - удалять все файлы в каталоге (а не только до освобождения нужного объема места на диске).
//
Процедура ОчиститьРабочийКаталог(ОбработчикРезультата, РазмерФайловВРабочемКаталоге, РазмерДобавляемогоФайла, ОчищатьВсе) Экспорт
	
#Если ВебКлиент Тогда
	ВернутьРезультатПослеПоказаПредупреждения(ОбработчикРезультата, НСтр("ru = 'Очистка рабочего каталога возможна только в приложении (тонкий клиент).'"), Неопределено);
	Возврат;
#КонецЕсли
	
	ПараметрыОбработчика = Новый Структура;
	ПараметрыОбработчика.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыОбработчика.Вставить("РазмерФайловВРабочемКаталоге", РазмерФайловВРабочемКаталоге);
	ПараметрыОбработчика.Вставить("РазмерДобавляемогоФайла", РазмерДобавляемогоФайла);
	ПараметрыОбработчика.Вставить("ОчищатьВсе", ОчищатьВсе);
	
	ОчиститьРабочийКаталогЗапуск(ПараметрыОбработчика);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ОчиститьРабочийКаталогЗапуск(ПараметрыВыполнения)
	
	ИмяКаталога = РабочийКаталогПользователя();
	
	ТаблицаФайлов = Новый Массив;
	МассивФайлов = НайтиФайлы(ИмяКаталога, "*");
	ОбходФайловТаблица(ИмяКаталога, МассивФайлов, ТаблицаФайлов);
	
	// Вызов сервера - для сортировки
	//  сортировка по дате - в начале будут самые давно помещенные в рабочий каталог.
	РаботаСФайламиСлужебныйВызовСервера.СортироватьМассивСтруктур(ТаблицаФайлов);
	
	ПерсональныеНастройки = ПерсональныеНастройкиРаботыСФайлами();
	МаксРазмер = ПерсональныеНастройки.МаксимальныйРазмерЛокальногоКэшаФайлов;
	
	СреднийРазмерФайла = 1000;
	Если ТаблицаФайлов.Количество() <> 0 Тогда
		СреднийРазмерФайла = ПараметрыВыполнения.РазмерФайловВРабочемКаталоге / ТаблицаФайлов.Количество();
	КонецЕсли;
	
	Если ПараметрыВыполнения.ОчищатьВсе Тогда
		СколькоНадоОсвободитьМеста = 0;
	Иначе
		СколькоНадоОсвободитьМеста = МаксРазмер / 10;
		Если СреднийРазмерФайла * 3 / 2 > СколькоНадоОсвободитьМеста Тогда
			СколькоНадоОсвободитьМеста = СреднийРазмерФайла * 3 / 2;
		КонецЕсли;
	КонецЕсли;
	
	СколькоОсталось = ПараметрыВыполнения.РазмерФайловВРабочемКаталоге + ПараметрыВыполнения.РазмерДобавляемогоФайла;
	ПараметрыВыполнения.Вставить("ИмяКаталога", ИмяКаталога);
	ПараметрыВыполнения.Вставить("МаксРазмер", МаксРазмер);
	ПараметрыВыполнения.Вставить("СколькоОсталось", СколькоОсталось);
	ПараметрыВыполнения.Вставить("СколькоНадоОсвободитьМеста", СколькоНадоОсвободитьМеста);
	ПараметрыВыполнения.Вставить("ТаблицаФайлов", ТаблицаФайлов);
	ОчиститьРабочийКаталогДляОткрываемогоФайла(ПараметрыВыполнения);
	
КонецПроцедуры

// Параметры:
//   ПараметрыВыполнения - Структура:
//     * ТаблицаФайлов - Массив из см. ДанныеФайловВРабочемКаталоге
//
Процедура ОчиститьРабочийКаталогДляОткрываемогоФайла(ПараметрыВыполнения)
	
	Индекс = 0;
	Заголовок = НСтр("ru = 'Очистка рабочего каталога'");
	Текст = НСтр("ru = 'Пожалуйста, подождите...'");
	Состояние(Заголовок, 1, Текст);
	Для каждого Элемент Из ПараметрыВыполнения.ТаблицаФайлов Цикл
		
		Индекс = Индекс + 1;
		
		ПолныйПуть = ПараметрыВыполнения.ИмяКаталога + Элемент.Путь;
		ФайлНаДиске = Новый Файл(ПолныйПуть);
		ФайлНаДиске.УстановитьТолькоЧтение(Ложь);
		УдалитьФайл(ПараметрыВыполнения, ПолныйПуть);
		
		ПутьСПодкаталогом = ПараметрыВыполнения.ИмяКаталога;
		Позиция = СтрНайти(Элемент.Путь, ПолучитьРазделительПути());
		Если Позиция <> 0 Тогда
			ПутьСПодкаталогом = ПараметрыВыполнения.ИмяКаталога + Лев(Элемент.Путь, Позиция);
		КонецЕсли;
		
		// Если каталог стал пуст - удалить его.
		МассивФайловВКаталоге = НайтиФайлы(ПутьСПодкаталогом, "*");
		Если МассивФайловВКаталоге.Количество() = 0 Тогда
			Если ПутьСПодкаталогом <> ПараметрыВыполнения.ИмяКаталога Тогда
				Попытка
					УдалитьФайлы(ПутьСПодкаталогом);
				Исключение
					ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
						"Предупреждение", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()),, Истина);
				КонецПопытки;	
			КонецЕсли;
		КонецЕсли;
		
		РаботаСФайламиСлужебныйВызовСервера.УдалитьИзРегистра(Элемент.Версия);
		
		Если ПараметрыВыполнения.СколькоНадоОсвободитьМеста > 0 Тогда
			ПараметрыВыполнения.СколькоОсталось = ПараметрыВыполнения.СколькоОсталось - Элемент.Размер;
			Если ПараметрыВыполнения.СколькоОсталось < ПараметрыВыполнения.МаксРазмер - ПараметрыВыполнения.СколькоНадоОсвободитьМеста Тогда
				Возврат; // Освободили достаточно - выход из цикла.
			КонецЕсли;
		КонецЕсли;
		
		Если Индекс % 10 = 0 Тогда
			Прогресс = ?(ПараметрыВыполнения.СколькоНадоОсвободитьМеста > 0,
				(ПараметрыВыполнения.СколькоНадоОсвободитьМеста - ПараметрыВыполнения.СколькоОсталось) * 100 / ПараметрыВыполнения.СколькоНадоОсвободитьМеста,
				Индекс * 100 / ПараметрыВыполнения.ТаблицаФайлов.Количество());
			Состояние(Заголовок, Прогресс, Текст);
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Получение файла с сервера и регистрация в локальном кэше.

// Получить Файл с сервера и зарегистрировать в локальном кэше.
//
// Параметры:
//   ПараметрыВыполнения - Структура:
//     * ОбработчикРезультата - ОписаниеОповещения
//                            - Неопределено - описание процедуры, принимающей результат работы.
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//     * ПолноеИмяФайлаВРабочемКаталоге - Строка - здесь возвращается полное имя файла.
//     * ДатаФайлаВБазе - Дата - дата файла в базе.
//     * НаЧтение - Булево - файл помещен на чтение.
//     * ИдентификаторФормы - УникальныйИдентификатор - идентификатор формы.
//
Процедура ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайлов(Знач ПараметрыВыполнения)
	
	ПараметрыВыполнения = ОбщегоНазначенияКлиент.СкопироватьРекурсивно(ПараметрыВыполнения);
	ПараметрыВыполнения.Вставить("ВРабочемКаталогеВладельца", ПараметрыВыполнения.ДанныеФайла.РабочийКаталогВладельца <> "");
	ПараметрыВыполнения.Вставить("ИмяКаталога", "");
	ПараметрыВыполнения.Вставить("ИмяКаталогаПрежнееЗначение", "");
	ПараметрыВыполнения.Вставить("ИмяФайла", "");
	ПараметрыВыполнения.Вставить("МаксимальнаяДлинаПолногоПути", 260);
	ПараметрыВыполнения.Вставить("ФайлПолучен", Ложь);
	
	Если ПараметрыВыполнения.ПолноеИмяФайла = "" Тогда
		ПараметрыВыполнения.ИмяКаталога = РабочийКаталогПользователя();
		ПараметрыВыполнения.ИмяКаталогаПрежнееЗначение = ПараметрыВыполнения.ИмяКаталога;
		
		// Формирование имени файла с расширением.
		ПараметрыВыполнения.ИмяФайла = ПараметрыВыполнения.ДанныеФайла.ПолноеНаименованиеВерсии;
		Если Не ПустаяСтрока(ПараметрыВыполнения.ДанныеФайла.Расширение) Тогда 
			ПараметрыВыполнения.ИмяФайла = ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(
				ПараметрыВыполнения.ИмяФайла, ПараметрыВыполнения.ДанныеФайла.Расширение);
		КонецЕсли;
		
		ОбщегоНазначенияСлужебныйКлиент.СократитьИмяФайла(ПараметрыВыполнения.ИмяФайла);
		
		ПараметрыВыполнения.ПолноеИмяФайла = "";
		Если Не ПустаяСтрока(ПараметрыВыполнения.ИмяФайла) Тогда
			ПараметрыВыполнения.ПолноеИмяФайла = ПараметрыВыполнения.ИмяКаталога 
				+ РаботаСФайламиСлужебныйКлиентСервер.УникальноеИмяСПутем(ПараметрыВыполнения.ИмяКаталога,
					ПараметрыВыполнения.ИмяФайла);
		КонецЕсли;
		
		Если ПустаяСтрока(ПараметрыВыполнения.ИмяФайла) Тогда
			ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
			Возврат;
		КонецЕсли;
		
		ПараметрыВыполнения.МаксимальнаяДлинаПолногоПути = 260;
		Если НРег(ПараметрыВыполнения.ДанныеФайла.Расширение) = "xls" Или НРег(ПараметрыВыполнения.ДанныеФайла.Расширение) = "xlsx" Тогда
			// Для Excel длина имени файла вместе с путем не должна превышать 218 знака.
			ПараметрыВыполнения.МаксимальнаяДлинаПолногоПути = 218;
		КонецЕсли;
		
		МаксимальнаяДлинаИмениФайла = ПараметрыВыполнения.МаксимальнаяДлинаПолногоПути - 5; // 5 - минимум для "C:\1\"
		
		Если ПараметрыВыполнения.ВРабочемКаталогеВладельца = Ложь Тогда
#Если Не ВебКлиент Тогда
			Если СтрДлина(ПараметрыВыполнения.ПолноеИмяФайла) > ПараметрыВыполнения.МаксимальнаяДлинаПолногоПути Тогда
				ПутьКаталогаПользователя = КаталогДанныхПользователя();
				МаксимальнаяДлинаИмениФайла = ПараметрыВыполнения.МаксимальнаяДлинаПолногоПути - СтрДлина(ПутьКаталогаПользователя);
				
				// Если  имя  файла плюс 5 превышает 260 - пишем "Измените имя  файла на более короткое. ОК" и выходим.
				Если СтрДлина(ПараметрыВыполнения.ИмяФайла) > МаксимальнаяДлинаИмениФайла Тогда
					
					ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Длина пути к файлу (рабочий каталог плюс имя файла) превышает %1 символов
						           |%2'"),
						ПараметрыВыполнения.МаксимальнаяДлинаПолногоПути,
						ПараметрыВыполнения.ПолноеИмяФайла);
					ТекстСообщения = ТекстСообщения + Символы.ВК + Символы.ВК
						+ НСтр("ru = 'Измените имя файла на более короткое.'");
					ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, 
						ТекстСообщения, ПараметрыВыполнения);
					Возврат;
					
				КонецЕсли;
				
				ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловПредложитьВыборКаталога(-1, ПараметрыВыполнения);
				Возврат;
				
			КонецЕсли;
#КонецЕсли
		КонецЕсли;
		
	КонецЕсли;
	
	ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловПродолжение(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловПредложитьВыборКаталога(Ответ, ПараметрыВыполнения)
	
	ТекстВопроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Длина пути к файлу превышает %1 символов:
		|%2
		|
		|Выбрать другой основной рабочий каталог?'"),
		ПараметрыВыполнения.МаксимальнаяДлинаПолногоПути,
		ПараметрыВыполнения.ПолноеИмяФайла);
	Обработчик = Новый ОписаниеОповещения("ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловНачатьВыборКаталога", ЭтотОбъект, ПараметрыВыполнения);
	ПоказатьВопрос(Обработчик, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловНачатьВыборКаталога(Ответ, ПараметрыВыполнения) Экспорт
	
	Если Ответ = КодВозвратаДиалога.Нет Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
		Возврат;
	КонецЕсли;
	
	// Выбираем другой путь к рабочему каталогу.
	Заголовок = НСтр("ru = 'Выберите другой основной рабочий каталог'");
	КаталогВыбран = ВыбратьПутьКРабочемуКаталогу(ПараметрыВыполнения.ИмяКаталога, Заголовок, Ложь);
	Если Не КаталогВыбран Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.ПолноеИмяФайла = ПараметрыВыполнения.ИмяКаталога 
		+ РаботаСФайламиСлужебныйКлиентСервер.УникальноеИмяСПутем(
		ПараметрыВыполнения.ИмяКаталога,
		ПараметрыВыполнения.ИмяФайла);
	
	// уложились в 260 символов
	Если СтрДлина(ПараметрыВыполнения.ПолноеИмяФайла) <= ПараметрыВыполнения.МаксимальнаяДлинаПолногоПути Тогда
		Обработчик = Новый ОписаниеОповещения("ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловПослеПереносаСодержимогоРабочегоКаталога", ЭтотОбъект, ПараметрыВыполнения);
		ПеренестиСодержимоеРабочегоКаталога(Обработчик, ПараметрыВыполнения.ИмяКаталогаПрежнееЗначение, ПараметрыВыполнения.ИмяКаталога);
	Иначе
		ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловПредложитьВыборКаталога(-1, ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловПослеПереносаСодержимогоРабочегоКаталога(СодержимоеПеренесено, ПараметрыВыполнения) Экспорт
	
	Если СодержимоеПеренесено Тогда
		УстановитьРабочийКаталогПользователя(ПараметрыВыполнения.ИмяКаталога);
		ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловПродолжение(ПараметрыВыполнения);
	Иначе
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения   - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//
Процедура ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловПродолжение(ПараметрыВыполнения)
	
#Если Не ВебКлиент Тогда
	Если ПараметрыВыполнения.ВРабочемКаталогеВладельца = Ложь Тогда
		ОсвободитьМестоВРабочемКаталоге(Неопределено, ПараметрыВыполнения.ДанныеФайла);
	КонецЕсли;
#КонецЕсли
	
	// Запись Файл в каталог
	ПараметрыВыполнения.ИмяФайла = ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(
		ПараметрыВыполнения.ДанныеФайла.ПолноеНаименованиеВерсии,
		ПараметрыВыполнения.ДанныеФайла.Расширение);
	ОбщегоНазначенияСлужебныйКлиент.СократитьИмяФайла(ПараметрыВыполнения.ИмяФайла);
	
	ФайлНаДискеПоИмени = Новый Файл(ПараметрыВыполнения.ПолноеИмяФайла);
	ИмяИРасширениеВПути = ФайлНаДискеПоИмени.Имя;
	Позиция = СтрНайти(ПараметрыВыполнения.ПолноеИмяФайла, ИмяИРасширениеВПути);
	ПутьКФайлу = "";
	Если Позиция <> 0 Тогда
		ПутьКФайлу = Лев(ПараметрыВыполнения.ПолноеИмяФайла, Позиция - 1); // -1 - вычет слэша
	КонецЕсли;
	
	ПутьКФайлу = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(ПутьКФайлу);
	ПараметрыВыполнения.Вставить("ПараметрПутьКФайлу", ПутьКФайлу);
	
	ПараметрыВыполнения.ПолноеИмяФайла = ПутьКФайлу + ПараметрыВыполнения.ИмяФайла; // могло смениться расширение
	
	Если ПараметрыВыполнения.ДанныеФайла.Свойство("ПутьОбновленияИзФайлаНаДиске") Тогда
		
		КопироватьФайл(ПараметрыВыполнения.ДанныеФайла.ПутьОбновленияИзФайлаНаДиске, ПараметрыВыполнения.ПолноеИмяФайла);
		ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловЗавершение(ПараметрыВыполнения);
		
		Возврат;
	КонецЕсли;
	
	Если ПараметрыВыполнения.ДанныеФайла.Зашифрован Тогда
		
		Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
			Возврат;
		КонецЕсли;
		
		ЗаполнитьВременныйИдентификаторФормы(ПараметрыВыполнения.ИдентификаторФормы, ПараметрыВыполнения);
		
		СтруктураВозврата = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИДвоичныеДанные(
			ПараметрыВыполнения.ДанныеФайла.Версия,, ПараметрыВыполнения.ИдентификаторФормы);
		
		ОписаниеДанных = Новый Структура;
		ОписаниеДанных.Вставить("Операция",              НСтр("ru = 'Расшифровка файла'"));
		ОписаниеДанных.Вставить("ЗаголовокДанных",       НСтр("ru = 'Файл'"));
		ОписаниеДанных.Вставить("Данные",                СтруктураВозврата.ДвоичныеДанные);
		ОписаниеДанных.Вставить("Представление",         ПараметрыВыполнения.ДанныеФайла.Ссылка);
		ОписаниеДанных.Вставить("СертификатыШифрования", ПараметрыВыполнения.ДанныеФайла.Ссылка);
		ОписаниеДанных.Вставить("СообщитьОЗавершении",   Ложь);
		
		ОбработчикПродолжения = Новый ОписаниеОповещения(
			"ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловПослеРасшифровки",
			ЭтотОбъект,
			ПараметрыВыполнения);
		
		МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
		МодульЭлектроннаяПодписьКлиент.Расшифровать(ОписаниеДанных, , ОбработчикПродолжения);
		
		Возврат;
	КонецЕсли;
	
	ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловПередачаФайла(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловПослеРасшифровки(ОписаниеДанных, ПараметрыВыполнения) Экспорт
	
	Если Не ОписаниеДанных.Успех Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(ОписаниеДанных.РасшифрованныеДанные) = Тип("ДвоичныеДанные") Тогда
		АдресФайла = ПоместитьВоВременноеХранилище(ОписаниеДанных.РасшифрованныеДанные,
			ПараметрыВыполнения.ИдентификаторФормы);
		ДанныеФайла = ПараметрыВыполнения.ОбработчикРезультата.ДополнительныеПараметры.ДанныеФайла;
		ДанныеФайла.Кодировка = РаботаСФайламиСлужебныйКлиентСервер.ОпределитьКодировкуДвоичныхДанных(ОписаниеДанных.РасшифрованныеДанные, ДанныеФайла.Расширение);
	Иначе
		АдресФайла = ОписаниеДанных.РасшифрованныеДанные;
	КонецЕсли;
	
	ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловПередачаФайла(ПараметрыВыполнения, АдресФайла);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловПередачаФайла(ПараметрыВыполнения, АдресФайла = Неопределено)
	
	Если АдресФайла = Неопределено Тогда
		Если ПараметрыВыполнения.ДанныеФайла.Версия <> ПараметрыВыполнения.ДанныеФайла.ТекущаяВерсия Тогда
			АдресФайла = РаботаСФайламиСлужебныйВызовСервера.ПолучитьНавигационнуюСсылкуДляОткрытия(
				ПараметрыВыполнения.ДанныеФайла.Версия, ПараметрыВыполнения.ИдентификаторФормы);
		Иначе
			АдресФайла = ПараметрыВыполнения.ДанныеФайла.СсылкаНаДвоичныеДанныеФайла;
		КонецЕсли;
	КонецЕсли;
	
	ПередаваемыеФайлы = Новый Массив;
	Описание = Новый ОписаниеПередаваемогоФайла(ПараметрыВыполнения.ПолноеИмяФайла, АдресФайла);
	ПередаваемыеФайлы.Добавить(Описание);
	
#Если ВебКлиент Тогда
	Если ПараметрыВыполнения.ДополнительныеПараметры <> Неопределено 
		И ПараметрыВыполнения.ДополнительныеПараметры.Свойство("ОткрытьФайл") Тогда
			
		МассивОпераций = Новый Массив;
		
		ОписаниеВызова = Новый Массив;
		ОписаниеВызова.Добавить("ПолучитьФайлы");
		ОписаниеВызова.Добавить(ПередаваемыеФайлы);
		ОписаниеВызова.Добавить(Неопределено);  // Не используется.
		ОписаниеВызова.Добавить(ПараметрыВыполнения.ПараметрПутьКФайлу);
		ОписаниеВызова.Добавить(Ложь);          // Интерактивно = Ложь.
		МассивОпераций.Добавить(ОписаниеВызова);
		
		ОписаниеВызова = Новый Массив;
		ОписаниеВызова.Добавить("ЗапуститьПриложение");
		ОписаниеВызова.Добавить(ПараметрыВыполнения.ПолноеИмяФайла);
		МассивОпераций.Добавить(ОписаниеВызова);
		
		Если Не ЗапроситьРазрешениеПользователя(МассивОпераций) Тогда
			// Пользователь не дал разрешения.
			ОчиститьВременныйИдентификаторФормы(ПараметрыВыполнения);
			ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
			Возврат;
		КонецЕсли;
		
	КонецЕсли;
#КонецЕсли
	
	ПолученныеФайлы = Новый Массив;
	Если Не ПолучитьФайлы(ПередаваемыеФайлы, ПолученныеФайлы , , Ложь) Тогда
		ОчиститьВременныйИдентификаторФормы(ПараметрыВыполнения);
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
		Возврат;
	КонецЕсли;
	
	// Для варианта с хранением файлов в томах файл удаляется из временного хранилища после получения.
	Если ЭтоАдресВременногоХранилища(АдресФайла) Тогда
		УдалитьИзВременногоХранилища(АдресФайла);
	КонецЕсли;
	
	// Установим время изменения файла таким, как оно указано в текущей версии.
	УстановитьУниверсальноеВремяИзменения(ПараметрыВыполнения.ПолноеИмяФайла, 
		ПараметрыВыполнения.ДанныеФайла.ДатаМодификацииУниверсальная);
	
	ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловЗавершение(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайловЗавершение(ПараметрыВыполнения)
	
	ФайлНаДиске = Новый Файл(ПараметрыВыполнения.ПолноеИмяФайла);
	
	// Т.к. размер на компьютере может отличаться от размера в базе (при добавлении в веб-клиенте).
	РазмерФайла = ФайлНаДиске.Размер();
	
	ФайлНаДиске.УстановитьТолькоЧтение(ПараметрыВыполнения.НаЧтение);
	
	ПараметрыВыполнения.ИмяКаталога = РабочийКаталогПользователя();
	
	РаботаСФайламиСлужебныйВызовСервера.ЗанестиИнформациюФайлаВРегистр(ПараметрыВыполнения.ДанныеФайла.Версия,
		ПараметрыВыполнения.ПолноеИмяФайла, ПараметрыВыполнения.ИмяКаталога, ПараметрыВыполнения.НаЧтение, РазмерФайла,
		ПараметрыВыполнения.ВРабочемКаталогеВладельца);
	
	Если ПараметрыВыполнения.ДанныеФайла.Размер <> РазмерФайла Тогда
		
		Если Не ПараметрыВыполнения.ДанныеФайла.Свойство("ПутьОбновленияИзФайлаНаДиске") Тогда
			
			РаботаСФайламиСлужебныйВызовСервера.ОбновитьРазмерФайлаИВерсии(ПараметрыВыполнения.ДанныеФайла, 
				РазмерФайла, ПараметрыВыполнения.ИдентификаторФормы);
			
			ОповеститьОбИзменении(ПараметрыВыполнения.ДанныеФайла.Ссылка);
			ОповеститьОбИзменении(ПараметрыВыполнения.ДанныеФайла.Версия);
			
			ПараметрыОповещения = ПараметрыОповещенияЗаписиФайла();
			ПараметрыОповещения.Файл = ПараметрыВыполнения.ДанныеФайла.Ссылка;
			ПараметрыОповещения.Событие = "ДанныеФайлаИзменены";
			ПараметрыОповещения.ЭтоНовый = Ложь;
			
			Оповестить("Запись_Файл", ПараметрыОповещения, ПараметрыВыполнения.ДанныеФайла.Ссылка);
		КонецЕсли;
	КонецЕсли;
	
	ОчиститьВременныйИдентификаторФормы(ПараметрыВыполнения);
	
	ПараметрыВыполнения.ФайлПолучен = Истина;
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Получение файла из хранилища в рабочий каталог.

// Получает Файл из хранилища файлов в рабочий каталог папки
// и возвращает путь к этому файлу.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  ДанныеФайла        - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//  ПолноеИмяФайла     - Строка - возвращаемое значение.
//  НаЧтение           - Булево - Ложь - для чтения, Истина для редактирования.
//  ИдентификаторФормы - УникальныйИдентификатор
//
Процедура ПолучитьФайлВерсииВРабочийКаталогПапки(ОбработчикРезультата, ДанныеФайла, ПолноеИмяФайла,
	НаЧтение, ИдентификаторФормы, ДополнительныеПараметры)
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("ДанныеФайла", ДанныеФайла);
	ПараметрыВыполнения.Вставить("ПолноеИмяФайла", ПолноеИмяФайла);
	ПараметрыВыполнения.Вставить("НаЧтение", НаЧтение);
	ПараметрыВыполнения.Вставить("ИдентификаторФормы", ИдентификаторФормы);
	ПараметрыВыполнения.Вставить("ДополнительныеПараметры", ДополнительныеПараметры);
	
	ПараметрыВыполнения.Вставить("ФайлПолучен", Ложь);
	
	// Формирование имени файла с расширением.
	ИмяФайла = ДанныеФайла.ПолноеНаименованиеВерсии;
	Если Не ПустаяСтрока(ДанныеФайла.Расширение) Тогда 
		ИмяФайла = ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(ИмяФайла, ДанныеФайла.Расширение);
	КонецЕсли;
	
	ОбщегоНазначенияСлужебныйКлиент.СократитьИмяФайла(ИмяФайла);
	
	Если ПараметрыВыполнения.ПолноеИмяФайла = "" Тогда
		ПараметрыВыполнения.ПолноеИмяФайла = ДанныеФайла.РабочийКаталогВладельца + ИмяФайла;
		Обработчик = Новый ОписаниеОповещения("ПолучитьФайлВерсииВРабочийКаталогПапкиПослеПроверкиДлиныПути", 
			ЭтотОбъект, ПараметрыВыполнения);
		ПроверитьМаксимальнуюДлинуПолногоПутиВРабочемКаталоге(Обработчик, ДанныеФайла, ПараметрыВыполнения.ПолноеИмяФайла, ИмяФайла);
	Иначе
		ПолучитьФайлВерсииВРабочийКаталогПапкиПродолжение(ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПолучитьФайлВерсииВРабочийКаталогПапкиПослеПроверкиДлиныПути(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат = Ложь Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
	Иначе
		ПолучитьФайлВерсииВРабочийКаталогПапкиПродолжение(ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПолучитьФайлВерсииВРабочийКаталогПапкиПродолжение(ПараметрыВыполнения)
	
	// Поиск регистрации файла в рабочем каталоге (полное имя с путем).
	НайденныеСвойства = РаботаСФайламиСлужебныйВызовСервера.НайтиВРегистреПоПути(ПараметрыВыполнения.ПолноеИмяФайла);
	ПараметрыВыполнения.Вставить("ФайлЕстьВРегистре", НайденныеСвойства.ФайлЕстьВРегистре);
	Версия            = НайденныеСвойства.Файл;
	Владелец          = НайденныеСвойства.Владелец;
	ВРегистреНаЧтение = НайденныеСвойства.ВРегистреНаЧтение;
	ВРегистреПапка    = НайденныеСвойства.ВРегистреПапка;
	
	ФайлНаДиске = Новый Файл(ПараметрыВыполнения.ПолноеИмяФайла);
	ФайлНаДискеСуществует = ФайлНаДиске.Существует();
	
	// Удаление регистрации файла, если он не существует.
	Если ПараметрыВыполнения.ФайлЕстьВРегистре И Не ФайлНаДискеСуществует Тогда
		РаботаСФайламиСлужебныйВызовСервера.УдалитьИзРегистра(Версия);
		ПараметрыВыполнения.ФайлЕстьВРегистре = Ложь;
	КонецЕсли;
	
	Если Не ПараметрыВыполнения.ФайлЕстьВРегистре И Не ФайлНаДискеСуществует Тогда
		ПолучитьССервераИЗарегистрироватьВРабочемКаталогеПапки(
			ПараметрыВыполнения.ОбработчикРезультата,
			ПараметрыВыполнения.ДанныеФайла,
			ПараметрыВыполнения.ПолноеИмяФайла,
			ПараметрыВыполнения.ДанныеФайла.ДатаМодификацииУниверсальная,
			ПараметрыВыполнения.НаЧтение,
			ПараметрыВыполнения.ИдентификаторФормы,
			ПараметрыВыполнения.ДополнительныеПараметры);
		Возврат;
	КонецЕсли;
	
	// Установлено, что в рабочем каталоге файл существует.
	
	Если ПараметрыВыполнения.ФайлЕстьВРегистре И Версия <> ПараметрыВыполнения.ДанныеФайла.ТекущаяВерсия Тогда
		
		Если Владелец = ПараметрыВыполнения.ДанныеФайла.Ссылка И ВРегистреНаЧтение = Истина Тогда
			// Если владелец версий файла совпадает и
			// существующий файл в рабочем каталоге зарегистрирован для чтения,
			// тогда можно заменить его другим файлом из хранилища.
			ПолучитьССервераИЗарегистрироватьВРабочемКаталогеПапки(
				ПараметрыВыполнения.ОбработчикРезультата,
				ПараметрыВыполнения.ДанныеФайла,
				ПараметрыВыполнения.ПолноеИмяФайла,
				ПараметрыВыполнения.ДанныеФайла.ДатаМодификацииУниверсальная,
				ПараметрыВыполнения.НаЧтение,
				ПараметрыВыполнения.ИдентификаторФормы,
				ПараметрыВыполнения.ДополнительныеПараметры);
			Возврат;
		КонецЕсли;
		
		Если ПараметрыВыполнения.ДанныеФайла.Владелец = ВРегистреПапка Тогда // Одна и та же папка.
			ТекстПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'В рабочем каталоге на компьютере уже есть файл
				           |""%1"",
				           |соответствующий другому файлу в программе.
				           |
				           |Рекомендуется переименовать один из файлов в программе.'"),
				ПараметрыВыполнения.ПолноеИмяФайла);
		Иначе
			ТекстПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'В рабочем каталоге на компьютере уже есть файл
				           |""%1"",
				           |соответствующий другому файлу в программе.
				           |
				           |Рекомендуется указать другой рабочий каталог для одной из папок в программе.
				           |(У двух папок не должно быть одинакового рабочего каталога).'"),
				ПараметрыВыполнения.ПолноеИмяФайла);
		КонецЕсли;
		
		ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, ТекстПредупреждения, ПараметрыВыполнения);
		Возврат;
	КонецЕсли;
	
	// Выяснено, что Файл в рабочем каталоге есть.
	// Либо файл незарегистрирован, либо зарегистрирован и версия совпадает.
	
	// Проверка даты изменения и принятие решения, что делать дальше.
	Обработчик = Новый ОписаниеОповещения("ПолучитьФайлВерсииВРабочийКаталогПапкиПослеВыбораДействия", ЭтотОбъект, ПараметрыВыполнения);
	
	ДействиеПриОткрытииФайлаВРабочемКаталоге(
		Обработчик,
		ПараметрыВыполнения.ПолноеИмяФайла,
		ПараметрыВыполнения.ДанныеФайла);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения - Структура:
//     * ДополнительныеПараметры - см. ПолучитьФайлВерсииВРабочийКаталогПапки.ДополнительныеПараметры
//
Процедура ПолучитьФайлВерсииВРабочийКаталогПапкиПослеВыбораДействия(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат = "ВзятьИзХранилищаИОткрыть" Тогда
		
		// В рабочем каталоге папки настройка подтверждения при удалении не используется.
		УдалитьФайлБезПодтверждения(ПараметрыВыполнения.ПолноеИмяФайла);
		ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайлов(ПараметрыВыполнения);
		
	ИначеЕсли Результат = "ОткрытьСуществующий" Тогда
		
		Если ПараметрыВыполнения.ДанныеФайла.ВРабочемКаталогеНаЧтение <> ПараметрыВыполнения.НаЧтение
			Или Не ПараметрыВыполнения.ФайлЕстьВРегистре Тогда
			
			ВРабочемКаталогеВладельца = ПараметрыВыполнения.ДанныеФайла.РабочийКаталогВладельца <> "";
			ПеререгистрироватьВРабочемКаталоге(ПараметрыВыполнения.ДанныеФайла.Версия, 
				ПараметрыВыполнения.ПолноеИмяФайла, ПараметрыВыполнения.НаЧтение, ВРабочемКаталогеВладельца);
		КонецЕсли;
		
		ПараметрыВыполнения.ФайлПолучен = Истина;
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
		
	Иначе // Результат = "Отмена".
		ПараметрыВыполнения.ПолноеИмяФайла = "";
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Получение файла с сервера и регистрация в рабочем каталоге.

// Получить Файл с сервера и зарегистрировать в рабочем каталоге.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  ДанныеФайла  - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//  ПолноеИмяФайлаВРабочемКаталоге - Строка - здесь возвращается полное имя файла.
//  ДатаФайлаВБазе - Дата - дата файла в базе.
//  НаЧтение - Булево - файл помещен на чтение.
//  ИдентификаторФормы - УникальныйИдентификатор - идентификатор формы.
//  ДополнительныеПараметры - Произвольный - дополнительные параметры обработки.
//
Процедура ПолучитьССервераИЗарегистрироватьВРабочемКаталогеПапки(ОбработчикРезультата, ДанныеФайла, 
	ПолноеИмяФайлаВРабочемКаталоге, ДатаФайлаВБазе, НаЧтение, ИдентификаторФормы, ДополнительныеПараметры)
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("ДанныеФайла", ДанныеФайла);
	ПараметрыВыполнения.Вставить("ПолноеИмяФайлаВРабочемКаталоге", ПолноеИмяФайлаВРабочемКаталоге);
	ПараметрыВыполнения.Вставить("ДатаФайлаВБазе", ДатаФайлаВБазе);
	ПараметрыВыполнения.Вставить("НаЧтение", НаЧтение);
	ПараметрыВыполнения.Вставить("ИдентификаторФормы", ИдентификаторФормы);
	ПараметрыВыполнения.Вставить("ДополнительныеПараметры", ДополнительныеПараметры);
	
	ПараметрыВыполнения.Вставить("ПолноеИмяФайла", "");
	ПараметрыВыполнения.Вставить("ФайлПолучен", Ложь);
	
	ВРабочемКаталогеНаЧтение = Истина;
	ВРабочемКаталогеВладельца = Ложь;
	
	ФайлВРабочемКаталоге = ФайлНаходитсяВЛокальномКэшеФайлов(ДанныеФайла,
		ДанныеФайла.Версия, ПараметрыВыполнения.ПолноеИмяФайла,
		ВРабочемКаталогеНаЧтение, ВРабочемКаталогеВладельца);
	Если Не ФайлВРабочемКаталоге Тогда
		ПараметрыВыполнения.Вставить("ПолноеИмяФайла", ПараметрыВыполнения.ПолноеИмяФайлаВРабочемКаталоге);
		ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайлов(ПараметрыВыполнения);
		Возврат;
	КонецЕсли;

	// Получаем путь файла в рабочем каталоге - с проверкой на уникальность.
	Если ПараметрыВыполнения.ПолноеИмяФайла = "" Тогда
		ОбщегоНазначенияКлиент.СообщитьПользователю(
			НСтр("ru = 'Не удалось получить файл из программы в рабочий каталог на компьютере.'"));
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
		Возврат;
	КонецЕсли;
	
	// Выяснено, что Файл в рабочем каталоге есть.
	// Проверка даты изменения и принятие решения, что делать дальше.
	Обработчик = Новый ОписаниеОповещения("ПолучитьССервераИЗарегистрироватьВРабочемКаталогеПапкиПослеВыбораДействия", 
		ЭтотОбъект, ПараметрыВыполнения);
	ДействиеПриОткрытииФайлаВРабочемКаталоге(Обработчик, ПараметрыВыполнения.ПолноеИмяФайла,
		ПараметрыВыполнения.ДанныеФайла);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения - Структура:
//     * ДополнительныеПараметры - см. ПолучитьССервераИЗарегистрироватьВРабочемКаталогеПапки.ДополнительныеПараметры
//
Процедура ПолучитьССервераИЗарегистрироватьВРабочемКаталогеПапкиПослеВыбораДействия(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат = "ВзятьИзХранилищаИОткрыть" Тогда
		
		// В рабочем каталоге папки настройка подтверждения при удалении не используется.
		УдалитьФайлБезПодтверждения(ПараметрыВыполнения.ПолноеИмяФайла);		
		ПолучитьССервераИЗарегистрироватьВЛокальномКэшеФайлов(ПараметрыВыполнения);
		
	ИначеЕсли Результат = "ОткрытьСуществующий" Тогда
		
		Если ПараметрыВыполнения.ДанныеФайла.ВРабочемКаталогеНаЧтение <> ПараметрыВыполнения.НаЧтение Тогда
			ВРабочемКаталогеВладельца = ПараметрыВыполнения.ДанныеФайла.РабочийКаталогВладельца <> "";
			ПеререгистрироватьВРабочемКаталоге(ПараметрыВыполнения.ДанныеФайла.Версия,
				ПараметрыВыполнения.ПолноеИмяФайла, ПараметрыВыполнения.НаЧтение, ВРабочемКаталогеВладельца);
		КонецЕсли;
		
		ПараметрыВыполнения.ФайлПолучен = Истина;
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
		
	Иначе // Результат = "Отмена".
		ПараметрыВыполнения.ПолноеИмяФайла = "";
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Проверка максимальной длины рабочего каталога с заменой и переносом файлов.

// Проверяет максимальную длину, если нужно - меняет рабочий каталог и переносит файлы.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  ДанныеФайла  - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//  ПолноеИмяФайла - Строка - полное имя файла.
//  НормальноеИмяФайла - Строка - имя файла без пути.
//
Процедура ПроверитьМаксимальнуюДлинуПолногоПутиВРабочемКаталоге(ОбработчикРезультата, ДанныеФайла, 
	ПолноеИмяФайла, НормальноеИмяФайла)
	
#Если ВебКлиент Тогда
	ВернутьРезультат(ОбработчикРезультата, Истина);
	Возврат;
#КонецЕсли
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("ДанныеФайла", ДанныеФайла);
	ПараметрыВыполнения.Вставить("ПолноеИмяФайла", ПолноеИмяФайла);
	ПараметрыВыполнения.Вставить("НормальноеИмяФайла", НормальноеИмяФайла);
	
	ПараметрыВыполнения.Вставить("ИмяКаталогаПрежнееЗначение", ДанныеФайла.РабочийКаталогВладельца);
	ПараметрыВыполнения.Вставить("МаксимальнаяДлинаПолногоПути", 260);
	Если НРег(ДанныеФайла.Расширение) = "xls" Или НРег(ДанныеФайла.Расширение) = "xlsx" Тогда
		// Для Excel длина имени файла вместе с путем не должна превышать 218 знака.
		ПараметрыВыполнения.МаксимальнаяДлинаПолногоПути = 218;
	КонецЕсли;
	
	МаксимальнаяДлинаИмениФайла = ПараметрыВыполнения.МаксимальнаяДлинаПолногоПути - 5; // 5 - минимум для "C:\1\"
	Если СтрДлина(ПараметрыВыполнения.ПолноеИмяФайла) <= ПараметрыВыполнения.МаксимальнаяДлинаПолногоПути Тогда
		ВернутьРезультат(ОбработчикРезультата, Истина);
		Возврат;
	КонецЕсли;
	
	ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Длина полного пути к файлу (рабочий каталог плюс имя файла) превышает %1 символов
		           |""%2"".'"),
		ПараметрыВыполнения.МаксимальнаяДлинаПолногоПути,
		ПараметрыВыполнения.ПолноеИмяФайла);
	
	ПутьКаталогаПользователя = КаталогДанныхПользователя();
	МаксимальнаяДлинаИмениФайла = ПараметрыВыполнения.МаксимальнаяДлинаПолногоПути - СтрДлина(ПутьКаталогаПользователя);
	
	// Если  имя  файла плюс 5 превышает 260 - пишем "Измените имя  файла на более короткое. ОК" и выходим.
	Если СтрДлина(ПараметрыВыполнения.НормальноеИмяФайла) > МаксимальнаяДлинаИмениФайла Тогда
		ТекстСообщения = ТекстСообщения + Символы.ВК + Символы.ВК
			+ НСтр("ru = 'Измените имя файла на более короткое.'");
		ВернутьРезультатПослеПоказаПредупреждения(ОбработчикРезультата, ТекстСообщения, Ложь);
		Возврат;
	КонецЕсли;
	
	// Если структура папок (путь к рабочему каталогу текущей папки) превышает 260-5 (1.txt), пишем "Измените имена папок
	// или перенесите текущую папку в другую папку".
	Если СтрДлина(ДанныеФайла.РабочийКаталогВладельца) > ПараметрыВыполнения.МаксимальнаяДлинаПолногоПути - 5 Тогда
		ТекстСообщения = ТекстСообщения + Символы.ВК + Символы.ВК
			+ НСтр("ru = 'Измените имена папок или перенесите текущую папку в другую папку.'");
		ВернутьРезультатПослеПоказаПредупреждения(ОбработчикРезультата, ТекстСообщения, Ложь);
		Возврат;
	КонецЕсли;
	
	ПроверитьМаксимальнуюДлинуПолногоПутиВРабочемКаталогеПредложитьВыборКаталога(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПроверитьМаксимальнуюДлинуПолногоПутиВРабочемКаталогеПредложитьВыборКаталога(ПараметрыВыполнения)
	
	ТекстВопроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Длина полного пути к файлу (рабочий каталог плюс имя файла) превышает %1 символов
		|""%2"".
		|
		|Выбрать другой основной рабочий каталог?
		|(Содержимое рабочего каталога будет перенесено в выбранный каталог).'"),
		ПараметрыВыполнения.МаксимальнаяДлинаПолногоПути, ПараметрыВыполнения.ПолноеИмяФайла);
	Обработчик = Новый ОписаниеОповещения("ПроверитьМаксимальнуюДлинуПолногоПутиВРабочемКаталогеНачатьВыборКаталога", ЭтотОбъект, ПараметрыВыполнения);
	ПоказатьВопрос(Обработчик, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПроверитьМаксимальнуюДлинуПолногоПутиВРабочемКаталогеНачатьВыборКаталога(Ответ, ПараметрыВыполнения) Экспорт
	
	Если Ответ = КодВозвратаДиалога.Нет Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	// Выбираем другой путь к рабочему каталогу.
	Заголовок = НСтр("ru = 'Выберите другой рабочий каталог'");
	КаталогВыбран = ВыбратьПутьКРабочемуКаталогу(ПараметрыВыполнения.ДанныеФайла.РабочийКаталогВладельца, Заголовок, Истина);
	Если Не КаталогВыбран Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.ПолноеИмяФайла = ПараметрыВыполнения.ДанныеФайла.РабочийКаталогВладельца + ПараметрыВыполнения.НормальноеИмяФайла;
	
	// уложились в 260 символов
	Если СтрДлина(ПараметрыВыполнения.ПолноеИмяФайла) <= ПараметрыВыполнения.МаксимальнаяДлинаПолногоПути Тогда
		Обработчик = Новый ОписаниеОповещения("ПроверитьМаксимальнуюДлинуПолногоПутиВРабочемКаталогеПослеПереносаСодержимогоРабочегоКаталога", ЭтотОбъект, ПараметрыВыполнения);
		ПеренестиСодержимоеРабочегоКаталога(Обработчик, ПараметрыВыполнения.ИмяКаталогаПрежнееЗначение, ПараметрыВыполнения.ДанныеФайла.РабочийКаталогВладельца);
	Иначе
		ПроверитьМаксимальнуюДлинуПолногоПутиВРабочемКаталогеПредложитьВыборКаталога(ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПроверитьМаксимальнуюДлинуПолногоПутиВРабочемКаталогеПослеПереносаСодержимогоРабочегоКаталога(СодержимоеПеренесено, ПараметрыВыполнения) Экспорт
	
	Если СодержимоеПеренесено Тогда
		// Регистр сведений ФайлыВРабочемКаталоге - сейчас там полный путь к файлу -
		// надо его менять - выделять общую часть и replace. -просто SQL запросом -
		// для текущего пользователя.
		РаботаСФайламиСлужебныйВызовСервера.СохранитьРабочийКаталогПапкиИЗаменитьПутиВРегистре(
			ПараметрыВыполнения.ДанныеФайла.Владелец,
			ПараметрыВыполнения.ДанныеФайла.РабочийКаталогВладельца,
			ПараметрыВыполнения.ИмяКаталогаПрежнееЗначение);
	КонецЕсли;
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, СодержимоеПеренесено);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Копирование содержимого из одного каталога в другой.

// Копирует все файлы в указанном каталоге в другой каталог.
//
// Параметры:
//   ОбработчикРезультата - ОписаниеОповещения
//                        - Неопределено - описание процедуры, принимающей результат работы метода.
//   КаталогИсточника  - Строка - прежнее имя каталога.
//   КаталогПриемника  - Строка - новое имя каталога.
//
Процедура СкопироватьСодержимоеКаталога(ОбработчикРезультата, Знач КаталогИсточника, Знач КаталогПриемника)
	
	Результат = Новый Структура;
	Результат.Вставить("ВозниклаОшибка",           Ложь);
	Результат.Вставить("ПолноеИмяСбойногоФайла",   "");
	Результат.Вставить("ИнформацияОбОшибке",       "");
	Результат.Вставить("СкопированныеФайлыИПапки", Новый Массив);
	Результат.Вставить("ОригинальныеФайлыИПапки",  Новый Массив);
	
	КопироватьСодержимоеКаталога(Результат, КаталогИсточника, КаталогПриемника);
	
	Если Результат.ВозниклаОшибка Тогда
		
		ТекстВопроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось скопировать файл
			           |""%1"".
			           |Возможно он занят другим приложением.
			           |
			           |Повторить операцию?'"),
			Результат.ПолноеИмяСбойногоФайла);
		
		ПараметрыВыполнения = Новый Структура;
		ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
		ПараметрыВыполнения.Вставить("КаталогИсточника", КаталогИсточника);
		ПараметрыВыполнения.Вставить("КаталогПриемника", КаталогПриемника);
		ПараметрыВыполнения.Вставить("Результат", Результат);
		
		Обработчик = Новый ОписаниеОповещения("СкопироватьСодержимоеКаталогаПослеОтветаНаВопрос", 
			ЭтотОбъект, ПараметрыВыполнения);
		
		ПоказатьВопрос(Обработчик, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
	Иначе
		ВернутьРезультат(ОбработчикРезультата, Результат);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СкопироватьСодержимоеКаталогаПослеОтветаНаВопрос(Ответ, ПараметрыВыполнения) Экспорт
	
	Если Ответ = КодВозвратаДиалога.Нет Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения.Результат);
	Иначе
		СкопироватьСодержимоеКаталога(
			ПараметрыВыполнения.ОбработчикРезультата,
			ПараметрыВыполнения.КаталогИсточника,
			ПараметрыВыполнения.КаталогПриемника);
	КонецЕсли;
	
КонецПроцедуры

// Копирует все файлы в указанном каталоге в другой каталог.
//
// Параметры:
//   Результат - Структура - результат копирования. См. СкопироватьСодержимоеКаталога(), возвращаемое значение.
//   КаталогИсточника  - Строка - прежнее имя каталога.
//   КаталогПриемника  - Строка - новое имя каталога.
//
Процедура КопироватьСодержимоеКаталога(Результат, КаталогИсточника, КаталогПриемника)
	
	КаталогПриемника = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(КаталогПриемника);
	КаталогИсточника = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(КаталогИсточника);
	
	СоздатьКаталог(КаталогПриемника);
	
	Результат.СкопированныеФайлыИПапки.Добавить(КаталогПриемника);
	Результат.ОригинальныеФайлыИПапки.Добавить(КаталогИсточника);
	
	ФайлыИсточника = НайтиФайлы(КаталогИсточника, "*");
	
	Для Каждого ФайлИсточника Из ФайлыИсточника Цикл
		
		ФайлИсточникаПолноеИмя = ФайлИсточника.ПолноеИмя;
		ФайлИсточникаИмя       = ФайлИсточника.Имя;
		ФайлПриемникаПолноеИмя = КаталогПриемника + ФайлИсточникаИмя;
		
		Если ФайлИсточника.ЭтоКаталог() Тогда
			
			КопироватьСодержимоеКаталога(Результат, ФайлИсточникаПолноеИмя, ФайлПриемникаПолноеИмя);
			Если Результат.ВозниклаОшибка Тогда
				Возврат;
			КонецЕсли;
			
		Иначе
			
			Результат.ОригинальныеФайлыИПапки.Добавить(ФайлИсточникаПолноеИмя);
			
			ФайлПриемника = Новый Файл(ФайлПриемникаПолноеИмя);
			Если ФайлПриемника.Существует() Тогда
				// Это нужно для обратного копирования - в этом случае файлы уже могут существовать.
				Результат.СкопированныеФайлыИПапки.Добавить(ФайлПриемникаПолноеИмя);
			Иначе
				Попытка
					КопироватьФайл(ФайлИсточникаПолноеИмя, ФайлПриемникаПолноеИмя);
				Исключение
					Результат.ВозниклаОшибка         = Истина;
					Результат.ИнформацияОбОшибке     = ИнформацияОбОшибке();
					Результат.ПолноеИмяСбойногоФайла = ФайлИсточникаПолноеИмя;
					Возврат;
				КонецПопытки;
				Результат.СкопированныеФайлыИПапки.Добавить(ФайлПриемникаПолноеИмя);
			КонецЕсли;
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Перенос содержимого рабочего каталога в новый.

// Переносит все файлы в рабочем каталоге в другой каталог (в том числе и взятые на редактирование).
//
// Параметры:
//   ОбработчикРезультата - ОписаниеОповещения
//                        - Неопределено - описание процедуры, принимающей результат работы метода.
//   КаталогИсточника - Строка - прежнее имя каталога.
//   КаталогПриемника - Строка - новое имя каталога.
//
Процедура ПеренестиСодержимоеРабочегоКаталога(ОбработчикРезультата, КаталогИсточника, КаталогПриемника) Экспорт
	
	// Новый путь является подмножеством старого. Это запрещено, т.к. может привести к зацикливанию.
	Если СтрНайти(НРег(КаталогПриемника), НРег(КаталогИсточника)) <> 0 Тогда
		ТекстПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Выбранный рабочий каталог
			           |""%1""
			           |входит в старый рабочий каталог
			           |""%2"".'"),
			КаталогПриемника,
			КаталогИсточника);
		ВернутьРезультатПослеПоказаПредупреждения(ОбработчикРезультата, ТекстПредупреждения, Ложь);
		Возврат;
	КонецЕсли;
	
	// Копирование файлов из старого каталога в новый.
	ПараметрыОбработчика = Новый Структура;
	ПараметрыОбработчика.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыОбработчика.Вставить("КаталогИсточника", КаталогИсточника);
	ПараметрыОбработчика.Вставить("КаталогПриемника", КаталогПриемника);
	Обработчик = Новый ОписаниеОповещения("ПеренестиСодержимоеРабочегоКаталогаПослеКопированияВНовыйКаталог", ЭтотОбъект, ПараметрыОбработчика);
	
	СкопироватьСодержимоеКаталога(Обработчик, КаталогИсточника, КаталогПриемника);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПеренестиСодержимоеРабочегоКаталогаПослеКопированияВНовыйКаталог(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат.ВозниклаОшибка Тогда
		// Возникла ошибка копирования, затем пользователь отменил операцию.
		
		Обработчик = Новый ОписаниеОповещения(
			"ПеренестиСодержимоеРабочегоКаталогаПослеОтменыИОчисткиПриемника",
			ЭтотОбъект,
			ПараметрыВыполнения);
		
		УдалитьСодержимоеКаталога(Обработчик, Результат.СкопированныеФайлыИПапки); // Очистка папки приемника.
	Иначе
		// Копирование прошло успешно. Очистка старого каталога.
		Обработчик = Новый ОписаниеОповещения(
			"ПеренестиСодержимоеРабочегоКаталогаПослеУспехаИОчисткиИсточника",
			ЭтотОбъект,
			ПараметрыВыполнения);
		
		УдалитьСодержимоеКаталога(Обработчик, Результат.ОригинальныеФайлыИПапки);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПеренестиСодержимоеРабочегоКаталогаПослеОтменыИОчисткиПриемника(КаталогПриемникаОчищен, ПараметрыВыполнения) Экспорт
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПеренестиСодержимоеРабочегоКаталогаПослеУспехаИОчисткиИсточника(КаталогИсточникаОчищен, ПараметрыВыполнения) Экспорт
	
	Если КаталогИсточникаОчищен Тогда
		// Старый каталог очищен. Все шаги операции успешно завершены.
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Истина);
	Иначе
		// Старый каталог не очищен. Откат всей операции.
		Обработчик = Новый ОписаниеОповещения("ПеренестиСодержимоеРабочегоКаталогаПослеУспехаИОтменыОчистки", ЭтотОбъект, ПараметрыВыполнения);
		СкопироватьСодержимоеКаталога(Обработчик, ПараметрыВыполнения.КаталогПриемника, ПараметрыВыполнения.КаталогИсточника);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПеренестиСодержимоеРабочегоКаталогаПослеУспехаИОтменыОчистки(Результат, ПараметрыВыполнения) Экспорт
	
	// Откат операции.
	Если Результат.ВозниклаОшибка Тогда
		// Надо предупредить, что даже во время отката операции произошла ошибка.
		ТекстПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось скопировать обратно содержимое каталога
			           |""%1""
			           |в каталог
			           |""%2"".'"),
			ПараметрыВыполнения.КаталогПриемника,
			ПараметрыВыполнения.КаталогИсточника);
		ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, ТекстПредупреждения, Ложь);
	Иначе
		// Откат операции прошел успешно.
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
	КонецЕсли;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Удаление массива путей переданных папок и файлов.

// Удаляет все файлы и папки из переданного массива.
//
// Параметры:
//   ОбработчикРезультата - ОписаниеОповещения
//                        - Неопределено - описание процедуры, принимающей результат работы метода.
//   СкопированныеФайлыИПапки - Массив из Строка - пути файлов и папок.
//
Процедура УдалитьСодержимоеКаталога(ОбработчикРезультата, СкопированныеФайлыИПапки)
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("СкопированныеФайлыИПапки", СкопированныеФайлыИПапки);
	УдалитьСодержимоеКаталогаЗапуск(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура УдалитьСодержимоеКаталогаЗапуск(ПараметрыВыполнения)
	
	ВерхняяГраница = ПараметрыВыполнения.СкопированныеФайлыИПапки.Количество() - 1;
	Для Индекс = 0 По ВерхняяГраница Цикл
		Путь = ПараметрыВыполнения.СкопированныеФайлыИПапки[ВерхняяГраница - Индекс];
		Файл = Новый Файл(Путь);
		Если Не Файл.Существует() Тогда
			Продолжить; // Например временный файл Word ~aaa.doc мог быть удален при закрытии Word.
		КонецЕсли;
		
		Попытка
			Если Файл.ЭтоФайл() И Файл.ПолучитьТолькоЧтение() Тогда
				Файл.УстановитьТолькоЧтение(Ложь);
			КонецЕсли;
			УдалитьФайлы(Путь);
		Исключение
			ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось удалить файл в рабочем каталоге:
					|""%1"". 
					|Возможно он занят другим приложением.
					|
					|%2'"),
				Путь, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
				"Предупреждение", ТекстСообщения,, Истина);
		КонецПопытки;
	КонецЦикла;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Истина);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Импорт файлов с проверкой размера.

// Импорт со вспомогательными операциями (проверка предельного размера, удаление файлов и показ
// ошибок при импорте).
//
// Параметры:
//  ПараметрыВыполнения - см. ПараметрыИмпортаФайлов.
//
Процедура ВыполнитьИмпортФайлов(Знач ПараметрыВыполнения) Экспорт
	
	СлужебныеПараметры = ОбщегоНазначенияКлиент.СкопироватьРекурсивно(ПараметрыВыполнения);
	Обработчик = Новый ОписаниеОповещения("ИмпортФайловПослеПроверкиРазмеров", ЭтотОбъект, СлужебныеПараметры);
	ПроверитьПредельныйРазмерФайлов(Обработчик, СлужебныеПараметры);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ИмпортФайловПослеПроверкиРазмеров(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат.Успех = Ложь Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.Вставить("КоличествоСуммарное", Результат.КоличествоСуммарное);
	Если ПараметрыВыполнения.КоличествоСуммарное = 0 Тогда
		ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, НСтр("ru = 'Нет файлов для добавления'"), Неопределено);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.Вставить("ПерваяПапкаСТакимЖеИменем", Неопределено);
	ПараметрыВыполнения.Вставить("ПапкаДляДобавленияТекущая", Неопределено);
	ПараметрыВыполнения.Вставить("ВыбранныеФайлыВГраница", ПараметрыВыполнения.ВыбранныеФайлы.Количество()-1);
	ПараметрыВыполнения.Вставить("ВыбранныеФайлыИндекс", -1);
	ПараметрыВыполнения.Вставить("Индикатор", 0);
	ПараметрыВыполнения.Вставить("Счетчик", 0);
	ПараметрыВыполнения.Вставить("МассивФайлов", Новый Массив);
	ПараметрыВыполнения.Вставить("МассивИменФайловСОшибками", Новый Массив);
	ПараметрыВыполнения.Вставить("МассивСтруктурВсехФайлов", Новый Массив);
	ПараметрыВыполнения.Вставить("МассивВсехПапок", Новый Массив);
	ПараметрыВыполнения.Вставить("МассивФайловЭтогоКаталога", Неопределено);
	ПараметрыВыполнения.Вставить("ИмяПапки", Неопределено);
	ПараметрыВыполнения.Вставить("Путь", Неопределено);
	ПараметрыВыполнения.Вставить("ПапкаУжеНайдена", Неопределено);
	
	ОбработчикЗавершения = Новый ОписаниеОповещения("ИмпортФайловЦиклПродолжитьИмпортПослеВопросовВРекурсии", ЭтотОбъект);
	ЗарегистрироватьОбработчикЗавершения(ПараметрыВыполнения, ОбработчикЗавершения);
	ИмпортФайловЦикл(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ИмпортФайловЦикл(ПараметрыВыполнения)
	
	ПараметрыВыполнения.ВыбранныеФайлыИндекс = ПараметрыВыполнения.ВыбранныеФайлыИндекс + 1;
	Для Индекс = ПараметрыВыполнения.ВыбранныеФайлыИндекс По ПараметрыВыполнения.ВыбранныеФайлыВГраница Цикл
		ПараметрыВыполнения.ВыбранныеФайлыИндекс = Индекс;
		ИмяФайла = ПараметрыВыполнения.ВыбранныеФайлы[Индекс];
		
		ВыбранныйФайл = Новый Файл(ИмяФайла.Значение);
		
		ВыбранКаталог = Ложь;
		Если ВыбранныйФайл.Существует() Тогда
			ВыбранКаталог = ВыбранныйФайл.ЭтоКаталог();
		КонецЕсли;
		
		Если ВыбранКаталог Тогда
			ПараметрыВыполнения.Путь = ИмяФайла.Значение;
			ПараметрыВыполнения.МассивФайловЭтогоКаталога = НайтиФайлыПсевдо(ПараметрыВыполнения.ПсевдоФайловаяСистема, ПараметрыВыполнения.Путь);
			
			ПараметрыВыполнения.ИмяПапки = ВыбранныйФайл.Имя;
			
			ПараметрыВыполнения.ПапкаУжеНайдена = Ложь;
			
			Если РаботаСФайламиСлужебныйВызовСервера.ЕстьПапкаСТакимИменем(
					ПараметрыВыполнения.ИмяПапки,
					ПараметрыВыполнения.ГруппаФайлов,
					ПараметрыВыполнения.ПерваяПапкаСТакимЖеИменем) Тогда
				ТекстВопроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Папка ""%1"" уже существует.
					           |
					           |Продолжить импорт папки?'"),
					ПараметрыВыполнения.ИмяПапки);
				Обработчик = Новый ОписаниеОповещения("ИмпортФайловЦиклПослеОтветаНаВопросПродолжить", ЭтотОбъект, ПараметрыВыполнения);
				ПоказатьВопрос(Обработчик, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
				Возврат;
			КонецЕсли;
			ИмпортФайловЦиклПродолжитьИмпорт(ПараметрыВыполнения);
			Если ПараметрыВыполнения.АсинхронныйДиалог.Открыт = Истина Тогда
				Возврат;
			КонецЕсли;
		Иначе
			ПараметрыВыполнения.МассивФайлов.Добавить(ВыбранныйФайл);
		КонецЕсли;
	КонецЦикла;
	
	Если ПараметрыВыполнения.МассивФайлов.Количество() <> 0 Тогда
		ОбработчикЗавершения = Новый ОписаниеОповещения("ИмпортФайловПослеЦиклаПослеВопросовВРекурсии", ЭтотОбъект);
		ЗарегистрироватьОбработчикЗавершения(ПараметрыВыполнения, ОбработчикЗавершения);
		ИмпортФайловРекурсивно(ПараметрыВыполнения.Владелец, ПараметрыВыполнения.МассивФайлов, ПараметрыВыполнения);
		
		Если ПараметрыВыполнения.АсинхронныйДиалог.Открыт = Истина Тогда
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	ИмпортФайловПослеЦиклаПродолжение(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ИмпортФайловЦиклПослеОтветаНаВопросПродолжить(Ответ, ПараметрыВыполнения) Экспорт
	
	Если Ответ <> КодВозвратаДиалога.Нет Тогда
		ИмпортФайловЦиклПродолжитьИмпорт(ПараметрыВыполнения);
	КонецЕсли;
	
	ИмпортФайловЦикл(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения   - Структура:
//     * МассивВсехПапок - Массив
//
Процедура ИмпортФайловЦиклПродолжитьИмпорт(ПараметрыВыполнения)
	
	Если Не ПараметрыВыполнения.ПапкаУжеНайдена Тогда
		РазделительПути = ПолучитьРазделительПути();
		РабочийКаталог  = ПараметрыВыполнения.Путь + ?(Прав(ПараметрыВыполнения.Путь, 1) = РазделительПути, "", РазделительПути);
		Если РаботаСФайламиСлужебныйКлиентПовтИсп.ЭтоСправочникФайлы(ПараметрыВыполнения.Владелец) Тогда
			ПараметрыВыполнения.ПапкаДляДобавленияТекущая = РаботаСФайламиСлужебныйВызовСервера.СоздатьПапкуФайлов(
				ПараметрыВыполнения.ИмяПапки, ПараметрыВыполнения.Владелец, , , РабочийКаталог);
		Иначе		
			ПараметрыВыполнения.ПапкаДляДобавленияТекущая = ПараметрыВыполнения.Владелец;
			ПараметрыВыполнения.ГруппаФайлов = РаботаСФайламиСлужебныйВызовСервера.СоздатьПапкуФайлов(
				ПараметрыВыполнения.ИмяПапки, ПараметрыВыполнения.Владелец, , ПараметрыВыполнения.ГруппаФайлов, РабочийКаталог);
		КонецЕсли;	
	КонецЕсли;
	
	// Собственно импорт
	ИмпортФайловРекурсивно(ПараметрыВыполнения.ПапкаДляДобавленияТекущая, ПараметрыВыполнения.МассивФайловЭтогоКаталога, ПараметрыВыполнения);
	Если ПараметрыВыполнения.АсинхронныйДиалог.Открыт = Истина Тогда
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.МассивВсехПапок.Добавить(ПараметрыВыполнения.Путь);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения   - Структура:
//     * МассивВсехПапок - Массив
//
Процедура ИмпортФайловЦиклПродолжитьИмпортПослеВопросовВРекурсии(Результат, ПараметрыВыполнения) Экспорт
	
	ПараметрыВыполнения.АсинхронныйДиалог.Открыт = Ложь;
	ПараметрыВыполнения.МассивВсехПапок.Добавить(ПараметрыВыполнения.Путь);
	ИмпортФайловЦикл(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ИмпортФайловПослеЦиклаПослеВопросовВРекурсии(Результат, ПараметрыВыполнения) Экспорт
	
	ИмпортФайловПослеЦиклаПродолжение(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ИмпортФайловПослеЦиклаПродолжение(ПараметрыВыполнения)
	
	Если ПараметрыВыполнения.МассивСтруктурВсехФайлов.Количество() > 1 Тогда
		ТекстСостояния = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Импорт файлов завершен. Импортировано файлов: %1'"), Строка(ПараметрыВыполнения.МассивСтруктурВсехФайлов.Количество()) );
		ПоказатьОповещениеПользователя(ТекстСостояния);
	КонецЕсли;
	
	Если ПараметрыВыполнения.УдалятьФайлыПослеДобавления = Истина Тогда
		УдалитьФайлыПослеДобавления(ПараметрыВыполнения.МассивСтруктурВсехФайлов, ПараметрыВыполнения.МассивВсехПапок);
	КонецЕсли;
	
	Если ПараметрыВыполнения.МассивСтруктурВсехФайлов.Количество() = 1 Тогда
		Элемент0 = ПараметрыВыполнения.МассивСтруктурВсехФайлов[0];
		Ссылка = ПолучитьНавигационнуюСсылку(Элемент0.Файл);
		ПоказатьОповещениеПользователя(
			НСтр("ru = 'Изменение:'"),
			Ссылка,
			Элемент0.Файл,
			БиблиотекаКартинок.Информация32);
	КонецЕсли;
	
	// Вывод сообщений об ошибках
	Если ПараметрыВыполнения.МассивИменФайловСОшибками.Количество() <> 0 Тогда
		Параметры = Новый Структура;
		Параметры.Вставить("МассивИменФайловСОшибками", ПараметрыВыполнения.МассивИменФайловСОшибками);
		
		ОткрытьФорму("Обработка.РаботаСФайлами.Форма.ФормаОтчета", Параметры);
	КонецЕсли;
	
	Если ПараметрыВыполнения.ВыбранныеФайлы.Количество() <> 1 Тогда
		ПараметрыВыполнения.ПапкаДляДобавленияТекущая = Неопределено;
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
	
КонецПроцедуры

// Удаляет файлы после импорта или загрузки.
Процедура УдалитьФайлыПослеДобавления(МассивСтруктурВсехФайлов, МассивВсехПапок)
	
	Для Каждого Элемент Из МассивСтруктурВсехФайлов Цикл
		ВыбранныйФайл = Новый Файл(Элемент.ИмяФайла);
		Попытка
			ВыбранныйФайл.УстановитьТолькоЧтение(Ложь);
			УдалитьФайлы(ВыбранныйФайл.ПолноеИмя);
		Исключение
			ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось удалить файл после добавления в программу:
					|""%1"". 
					|Возможно он занят другим приложением.
					|
					|%2'"),
				ВыбранныйФайл.ПолноеИмя, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
				"Предупреждение", ТекстСообщения,, Истина);
		КонецПопытки;	
	КонецЦикла;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Сохранение файла на компьютер

// Сохранение файла на компьютер.
// 
// Параметры:
//   ОбработчикРезультата - ОписаниеОповещения
//                        - Неопределено - описание процедуры, принимающей результат работы метода.
//   ДанныеФайла  - Структура
//   УникальныйИдентификатор - УникальныйИдентификатор - идентификатор формы..
//
Процедура СохранитьКак(ОбработчикРезультата, ДанныеФайла, УникальныйИдентификатор) Экспорт
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("ДанныеФайла", ДанныеФайла);
	ПараметрыВыполнения.Вставить("УникальныйИдентификатор", УникальныйИдентификатор);
	
	Если РасширениеРаботыСФайламиПодключено() Тогда
		СохранитьКакСРасширением(ПараметрыВыполнения);
	Иначе
		СохранитьКакБезРасширения(ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения   - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//
Процедура СохранитьКакСРасширением(ПараметрыВыполнения)
	
	// Проверим - если файл уже есть в кэше, и он новее чем в базе - дадим диалог с выбором.
	ПараметрыВыполнения.Вставить("ПутьКФайлуВКэше", "");
	Если ПараметрыВыполнения.ДанныеФайла.ФайлРедактируетТекущийПользователь Тогда
		ВРабочемКаталогеНаЧтение = Истина;
		ВРабочемКаталогеВладельца = Ложь;
		ПараметрыВыполнения.Вставить("ПолноеИмяФайла", "");
		
		ФайлВРабочемКаталоге = ФайлНаходитсяВЛокальномКэшеФайлов(ПараметрыВыполнения.ДанныеФайла, ПараметрыВыполнения.ДанныеФайла.Версия, ПараметрыВыполнения.ПолноеИмяФайла, ВРабочемКаталогеНаЧтение, ВРабочемКаталогеВладельца);
		Если ФайлВРабочемКаталоге Тогда
			
			ДатаФайлаВБазе = ПараметрыВыполнения.ДанныеФайла.ДатаМодификацииУниверсальная;
			
			ФайлВерсии = Новый Файл(ПараметрыВыполнения.ПолноеИмяФайла);
			ДатаФайлаНаДиске = ФайлВерсии.ПолучитьУниверсальноеВремяИзменения();
			
			Если ДатаФайлаНаДиске > ДатаФайлаВБазе Тогда // В рабочем каталоге более новый (изменен пользователем со стороны).
				ПараметрыОткрытияФормы = Новый Структура;
				ПараметрыОткрытияФормы.Вставить("Файл", ПараметрыВыполнения.ПолноеИмяФайла);
				
				Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Дата изменения файла ""%1""
					           |в рабочем каталоге на компьютере более поздняя (новее), чем в программе.
					           |Возможно, файл на компьютере был отредактирован.'"),
					Строка(ПараметрыВыполнения.ДанныеФайла.Ссылка));
				
				ПараметрыОткрытияФормы.Вставить("Сообщение", Сообщение);
				
				Обработчик = Новый ОписаниеОповещения("СохранитьКакСРасширениемПослеОтветаНаВопросДатаНовее", ЭтотОбъект, ПараметрыВыполнения);
				ОткрытьФорму("Обработка.РаботаСФайлами.Форма.РежимСозданияФайлаДляСохранитьКак", ПараметрыОткрытияФормы, , , , , Обработчик, РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);
				Возврат;
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	СохранитьКакСРасширениемПродолжение(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьКакСРасширениемПослеОтветаНаВопросДатаНовее(Ответ, ПараметрыВыполнения) Экспорт
	
	Если Ответ = КодВозвратаДиалога.Отмена Или Ответ = Неопределено Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, "");
		Возврат;
	КонецЕсли;
	
	Если Ответ = 1 Тогда // На основе файла на локальном компьютере.
		ПараметрыВыполнения.ПутьКФайлуВКэше = ПараметрыВыполнения.ПолноеИмяФайла;
	КонецЕсли;
	
	СохранитьКакСРасширениемПродолжение(ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьКакСРасширениемПродолжение(ПараметрыВыполнения)
	
	ПараметрыВыполнения.Вставить("ПутьВыбора", ПараметрыВыполнения.ДанныеФайла.ПапкаДляСохранитьКак);
	Если ПараметрыВыполнения.ПутьВыбора = Неопределено Или ПараметрыВыполнения.ПутьВыбора = "" Тогда
		ПараметрыВыполнения.ПутьВыбора = КаталогМоиДокументы();
	КонецЕсли;
	
	ПараметрыВыполнения.Вставить("СохранятьСРасшифровкой", Ложь);
	ПараметрыВыполнения.Вставить("РасширениеДляЗашифрованныхФайлов", "");
	
	Если ПараметрыВыполнения.ДанныеФайла.Зашифрован Тогда
		Обработчик = Новый ОписаниеОповещения("СохранитьКакСРасширениемПослеВыбораРежимаСохранения",
			ЭтотОбъект, ПараметрыВыполнения);
		
		ОткрытьФорму("Обработка.РаботаСФайлами.Форма.ВыборСохраненияШифрованногоФайла", , , , , ,
			Обработчик, РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);
	Иначе
		СохранитьКакСРасширениемПослеВыбораРежимаСохранения(-1, ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения   - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//
Процедура СохранитьКакСРасширениемПослеВыбораРежимаСохранения(Результат, ПараметрыВыполнения) Экспорт
	
	Если ТипЗнч(Результат) = Тип("Структура") Тогда
		ПараметрыВыполнения.РасширениеДляЗашифрованныхФайлов = Результат.РасширениеДляЗашифрованныхФайлов;
		
		Если Результат.СохранятьСРасшифровкой = 1 Тогда
			ПараметрыВыполнения.СохранятьСРасшифровкой = Истина;
		Иначе
			ПараметрыВыполнения.СохранятьСРасшифровкой = Ложь;
		КонецЕсли;
		
	ИначеЕсли Результат <> -1 Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, "");
		Возврат;
	КонецЕсли;
	
	Если Не ПараметрыВыполнения.СохранятьСРасшифровкой Тогда
		СохранитьКакСРасширениемПослеРасшифровки(-1, ПараметрыВыполнения);
		Возврат;
	КонецЕсли;
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		Возврат;
	КонецЕсли;
	
	СтруктураВозврата = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИДвоичныеДанные(ПараметрыВыполнения.ДанныеФайла.Версия,, 
		ПараметрыВыполнения.УникальныйИдентификатор);
	
	ОписаниеДанных = Новый Структура;
	ОписаниеДанных.Вставить("Операция",              НСтр("ru = 'Расшифровка файла'"));
	ОписаниеДанных.Вставить("ЗаголовокДанных",       НСтр("ru = 'Файл'"));
	ОписаниеДанных.Вставить("Данные",                СтруктураВозврата.ДвоичныеДанные);
	ОписаниеДанных.Вставить("Представление",         ПараметрыВыполнения.ДанныеФайла.Ссылка);
	ОписаниеДанных.Вставить("СертификатыШифрования", ПараметрыВыполнения.ДанныеФайла.Ссылка);
	ОписаниеДанных.Вставить("СообщитьОЗавершении",   Ложь);
	
	ОбработчикПродолжения = Новый ОписаниеОповещения("СохранитьКакСРасширениемПослеРасшифровки", ЭтотОбъект, ПараметрыВыполнения);
	
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	МодульЭлектроннаяПодписьКлиент.Расшифровать(ОписаниеДанных, , ОбработчикПродолжения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения   - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//
Процедура СохранитьКакСРасширениемПослеРасшифровки(ОписаниеДанных, ПараметрыВыполнения) Экспорт
	
	Если ОписаниеДанных <> -1 Тогда
		Если Не ОписаниеДанных.Успех Тогда
			ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
			Возврат;
		КонецЕсли;
	
		Если ТипЗнч(ОписаниеДанных.РасшифрованныеДанные) = Тип("ДвоичныеДанные") Тогда
			АдресФайла = ПоместитьВоВременноеХранилище(ОписаниеДанных.РасшифрованныеДанные,
				ПараметрыВыполнения.УникальныйИдентификатор);
		Иначе
			АдресФайла = ОписаниеДанных.РасшифрованныеДанные;
		КонецЕсли;
	Иначе
		Если ПараметрыВыполнения.ДанныеФайла.Свойство("СсылкаНаДвоичныеДанныеФайла") Тогда
			АдресФайла = ПараметрыВыполнения.ДанныеФайла.СсылкаНаДвоичныеДанныеФайла;
			ПараметрыВыполнения.ДанныеФайла.Вставить("ПолноеНаименованиеВерсии", ПараметрыВыполнения.ДанныеФайла.Наименование);
		Иначе
			АдресФайла = ПараметрыВыполнения.ДанныеФайла.НавигационнаяСсылкаТекущейВерсии;
			Если ПараметрыВыполнения.ДанныеФайла.ТекущаяВерсия <> ПараметрыВыполнения.ДанныеФайла.Версия Тогда
				АдресФайла = РаботаСФайламиСлужебныйВызовСервера.ПолучитьНавигационнуюСсылкуДляОткрытия(
					ПараметрыВыполнения.ДанныеФайла.Версия, ПараметрыВыполнения.УникальныйИдентификатор);
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	ИмяСРасширением = ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(
		ПараметрыВыполнения.ДанныеФайла.ПолноеНаименованиеВерсии, ПараметрыВыполнения.ДанныеФайла.Расширение);
	
	Расширение = ПараметрыВыполнения.ДанныеФайла.Расширение;
	
	Если ПараметрыВыполнения.ДанныеФайла.Зашифрован
	   И Не ПараметрыВыполнения.СохранятьСРасшифровкой Тогда
		
		Если Не ПустаяСтрока(ПараметрыВыполнения.РасширениеДляЗашифрованныхФайлов) Тогда
			ИмяСРасширением = ИмяСРасширением + "." + ПараметрыВыполнения.РасширениеДляЗашифрованныхФайлов;
			Расширение = ПараметрыВыполнения.РасширениеДляЗашифрованныхФайлов;
		КонецЕсли;
	КонецЕсли;
	
	ВыборФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
	ВыборФайла.МножественныйВыбор = Ложь;
	ВыборФайла.ПолноеИмяФайла = ИмяСРасширением;
	ВыборФайла.Расширение = Расширение;
	Фильтр = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Все файлы (*.%1)|*.%1'"), Расширение);
	ВыборФайла.Фильтр = Фильтр;
	ВыборФайла.Каталог = ПараметрыВыполнения.ПутьВыбора;
	
	Если Не ВыборФайла.Выбрать() Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Новый Структура);
		Возврат;
	КонецЕсли;
	
	ПолноеИмяФайла = ВыборФайла.ПолноеИмяФайла;
	
	Файл = Новый Файл(ПолноеИмяФайла);
	
	Если Файл.Существует() Тогда
		Если ПараметрыВыполнения.ПутьКФайлуВКэше <> ПолноеИмяФайла Тогда
			Попытка
				Файл.УстановитьТолькоЧтение(Ложь);
				УдалитьФайлы(ВыборФайла.ПолноеИмяФайла);
			Исключение
				ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
					"Предупреждение", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()),, Истина);
			КонецПопытки;	
		КонецЕсли;
	КонецЕсли;
	
	Если ПараметрыВыполнения.ПутьКФайлуВКэше <> "" Тогда
		Если ПараметрыВыполнения.ПутьКФайлуВКэше <> ПолноеИмяФайла Тогда
			КопироватьФайл(ПараметрыВыполнения.ПутьКФайлуВКэше, ВыборФайла.ПолноеИмяФайла);
		КонецЕсли;
	Иначе
		ПередаваемыеФайлы = Новый Массив;
		Описание = Новый ОписаниеПередаваемогоФайла(ПолноеИмяФайла, АдресФайла);
		ПередаваемыеФайлы.Добавить(Описание);
		
		ПутьКФайлу = Файл.Путь;
		ПутьКФайлу = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(ПутьКФайлу);
		
		Если ПолучитьФайлы(ПередаваемыеФайлы,, ПутьКФайлу, Ложь) Тогда
			
			// Для варианта с хранением файлов в томах удаляем Файл из временного хранилища после получения.
			Если ЭтоАдресВременногоХранилища(АдресФайла) Тогда
				УдалитьИзВременногоХранилища(АдресФайла);
			КонецЕсли;
			
			УстановитьУниверсальноеВремяИзменения(ПолноеИмяФайла, 
				ПараметрыВыполнения.ДанныеФайла.ДатаМодификацииУниверсальная);
			
		КонецЕсли;
	КонецЕсли;
	
	ПоказатьОповещениеПользователя(НСтр("ru = 'Файл успешно сохранен'"), , ПолноеИмяФайла);
	
	ПутьВыбораПрежний = ПараметрыВыполнения.ПутьВыбора;
	ПараметрыВыполнения.ПутьВыбора = Файл.Путь;
	Если ПутьВыбораПрежний <> ПараметрыВыполнения.ПутьВыбора Тогда
		ОбщегоНазначенияВызовСервера.ХранилищеОбщихНастроекСохранить("НастройкиПрограммы", "ПапкаДляСохранитьКак", ПараметрыВыполнения.ПутьВыбора);
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Новый Структура("ПолноеИмяФайла", ПолноеИмяФайла));
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьКакБезРасширения(ПараметрыВыполнения)
	
	ПараметрыВыполнения.Вставить("СохранятьСРасшифровкой", Ложь);
	ПараметрыВыполнения.Вставить("РасширениеДляЗашифрованныхФайлов", "");
	
	Если ПараметрыВыполнения.ДанныеФайла.Зашифрован Тогда
		Обработчик = Новый ОписаниеОповещения("СохранитьКакБезРасширенияПослеВыбораРежимаСохранения",
			ЭтотОбъект, ПараметрыВыполнения);
		
		ОткрытьФорму("Обработка.РаботаСФайлами.Форма.ВыборСохраненияШифрованногоФайла", , , , , ,
			Обработчик, РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);
	Иначе
		СохранитьКакБезРасширенияПослеВыбораРежимаСохранения(-1, ПараметрыВыполнения);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьКакБезРасширенияПослеВыбораРежимаСохранения(Результат, ПараметрыВыполнения) Экспорт
	
	Если ТипЗнч(Результат) = Тип("Структура") Тогда
		ПараметрыВыполнения.РасширениеДляЗашифрованныхФайлов = Результат.РасширениеДляЗашифрованныхФайлов;
		
		Если Результат.СохранятьСРасшифровкой = 1 Тогда
			ПараметрыВыполнения.СохранятьСРасшифровкой = Истина;
		Иначе
			ПараметрыВыполнения.СохранятьСРасшифровкой = Ложь;
		КонецЕсли;
		
	ИначеЕсли Результат <> -1 Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, "");
		Возврат;
	КонецЕсли;
	
	ЗаполнитьВременныйИдентификаторФормы(ПараметрыВыполнения.УникальныйИдентификатор, ПараметрыВыполнения);
	
	Обработчик = Новый ОписаниеОповещения("СохранитьКакБезРасширенияЗавершение", ЭтотОбъект, ПараметрыВыполнения);
	ОткрытьФайлБезРасширения(Обработчик, ПараметрыВыполнения.ДанныеФайла, ПараметрыВыполнения.УникальныйИдентификатор,
		Ложь, ПараметрыВыполнения.СохранятьСРасшифровкой, ПараметрыВыполнения.РасширениеДляЗашифрованныхФайлов);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура СохранитьКакБезРасширенияЗавершение(Результат, ПараметрыВыполнения) Экспорт
	
	ОчиститьВременныйИдентификаторФормы(ПараметрыВыполнения);
	
	Если Результат <> Истина Тогда
		Возврат;
	КонецЕсли;
	
	Если Не ПараметрыВыполнения.СохранятьСРасшифровкой
	   И ПараметрыВыполнения.ДанныеФайла.Зашифрован
	   И ЗначениеЗаполнено(ПараметрыВыполнения.РасширениеДляЗашифрованныхФайлов) Тогда
		
		Расширение = ПараметрыВыполнения.РасширениеДляЗашифрованныхФайлов;
	Иначе
		Расширение = ПараметрыВыполнения.ДанныеФайла.Расширение;
	КонецЕсли;
	
	ИмяФайла = ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(
		ПараметрыВыполнения.ДанныеФайла.ПолноеНаименованиеВерсии, Расширение);
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Новый Структура("ПолноеИмяФайла", ИмяФайла));
	
КонецПроцедуры

// Продолжение процедуры РаботаСФайламиКлиент.СохранитьФайлКак.
Процедура СохранитьФайлКакПослеСохранения(Результат, ОбработчикЗавершения) Экспорт
	
	Если ОбработчикЗавершения = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ПутьКФайлу = "";
	Если ТипЗнч(Результат) = Тип("Структура")
		И Результат.Свойство("ПолноеИмяФайла") Тогда
		
		ПутьКФайлу = Результат.ПолноеИмяФайла;
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(ОбработчикЗавершения, ПутьКФайлу);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Показывает напоминание перед помещением файла, если оно настроено.

// Покажет напоминание - если стоит настройка.
//
// Параметры:
//   ОбработчикРезультата - ОписаниеОповещения
//                        - Неопределено - описание процедуры, принимающей результат работы метода.
//
Процедура ПоказатьНапоминаниеПередПоместитьФайл(ОбработчикРезультата)
	
	ПерсональныеНастройки = ПерсональныеНастройкиРаботыСФайлами();
	Если ПерсональныеНастройки.ПоказыватьПодсказкиПриРедактированииФайлов = Истина Тогда
		Если Не РасширениеРаботыСФайламиПодключено() Тогда
			ТекстНапоминания = 
				НСтр("ru = 'Сейчас будет предложено выбрать файл для того,
				|чтобы поместить его в программу и закончить редактирование.
				|
				|Найдите нужный файл в том каталоге, который был
				|указан ранее при начале редактирования.'");
				
			Кнопки = Новый СписокЗначений;
			Кнопки.Добавить("Продолжить", НСтр("ru = 'Продолжить'"));
			Кнопки.Добавить("Отмена", НСтр("ru = 'Отмена'"));
			ПараметрыНапоминания = Новый Структура;
			ПараметрыНапоминания.Вставить("Картинка", БиблиотекаКартинок.Информация32);
			ПараметрыНапоминания.Вставить("ТекстФлажка",
				НСтр("ru = 'Больше не показывать это сообщение'"));
			ПараметрыНапоминания.Вставить("Заголовок",
				НСтр("ru = 'Помещение файла'"));
			СтандартныеПодсистемыКлиент.ПоказатьВопросПользователю(
				ОбработчикРезультата, ТекстНапоминания, Кнопки, ПараметрыНапоминания);
			Возврат;
		КонецЕсли;
	КонецЕсли;
	ВернутьРезультат(ОбработчикРезультата, Истина);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Проверяет размер файлов.

// Проверить предельный размер файлов.
// Возвращает Ложь, если есть файлы, превышающие предельный размер,
// и пользователь в диалоге предупреждения о наличии таких файлов выбрал "Отмена".
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  ПараметрыПроверки - Структура:
//    * ВыбранныеФайлы - Массив - массив объектов "Файл".
//    * Рекурсивно - Булево - рекурсивно обходить подкаталоги.
//    * ПсевдоФайловаяСистема - Соответствие - для строки (каталога) возвращает массив
//                                             строк (подкаталоги и файлы).
//
Процедура ПроверитьПредельныйРазмерФайлов(ОбработчикРезультата, ПараметрыПроверки)
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("КоличествоСуммарное", 0);
	ПараметрыВыполнения.Вставить("Успех", Ложь);
	
	МассивСлишкомБольшихФайлов = Новый Массив;
	
	Путь = "";
	
	МассивФайлов = Новый Массив;
	
	Для Каждого ИмяФайла Из ПараметрыПроверки.ВыбранныеФайлы Цикл
		
		Путь = ИмяФайла.Значение;
		ВыбранныйФайл = Новый Файл(Путь);
		
		ВыбранныйФайл = Новый Файл(ИмяФайла.Значение);
		ВыбранКаталог = Ложь;
		
		Если ВыбранныйФайл.Существует() Тогда
			ВыбранКаталог = ВыбранныйФайл.ЭтоКаталог();
		КонецЕсли;
		
		Если ВыбранКаталог Тогда
			МассивФайловЭтогоКаталога = НайтиФайлыПсевдо(ПараметрыПроверки.ПсевдоФайловаяСистема, Путь);
			НайтиСлишкомБольшиеФайлы(МассивФайловЭтогоКаталога, МассивСлишкомБольшихФайлов, ПараметрыПроверки.Рекурсивно, 
				ПараметрыВыполнения.КоличествоСуммарное, ПараметрыПроверки.ПсевдоФайловаяСистема);
		Иначе
			МассивФайлов.Добавить(ВыбранныйФайл);
		КонецЕсли;
	КонецЦикла;
	
	Если МассивФайлов.Количество() <> 0 Тогда
		НайтиСлишкомБольшиеФайлы(МассивФайлов, МассивСлишкомБольшихФайлов, ПараметрыПроверки.Рекурсивно, 
			ПараметрыВыполнения.КоличествоСуммарное, ПараметрыПроверки.ПсевдоФайловаяСистема);
	КонецЕсли;
	
	// Был хоть один слишком большой файл.
	Если МассивСлишкомБольшихФайлов.Количество() <> 0 Тогда 
		ФайлыБольшие = Новый СписокЗначений;
		Параметры = Новый Структура;
		
		Для Каждого Файл Из МассивСлишкомБольшихФайлов Цикл
			БольшойФайл = Новый Файл(Файл);
			РазмерФайлаВМб = Цел(БольшойФайл.Размер() / (1024 * 1024));
			ТекстСтроки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '%1 (%2 МБ)'"), Строка(Файл), Строка(РазмерФайлаВМб));
			ФайлыБольшие.Добавить(ТекстСтроки);
		КонецЦикла;
		
		Параметры.Вставить("ФайлыБольшие", ФайлыБольшие);
		Параметры.Вставить("Заголовок", НСтр("ru = 'Предупреждение при загрузке файлов'"));
		
		Обработчик = Новый ОписаниеОповещения("ПроверитьПредельныйРазмерФайловПослеОтветаНаВопрос", ЭтотОбъект, ПараметрыВыполнения);
		ОткрытьФорму("Обработка.РаботаСФайлами.Форма.ВопросПриИмпортеФайлов", Параметры, , , , , Обработчик, РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.Успех = Истина;
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ПроверитьПредельныйРазмерФайловПослеОтветаНаВопрос(Ответ, ПараметрыВыполнения) Экспорт
	
	ПараметрыВыполнения.Успех = (Ответ = КодВозвратаДиалога.ОК);
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Показывает информацию о том, что файл не был изменен.

// Покажет напоминание - если стоит настройка.
//
// Параметры:
//   ОбработчикРезультата - ОписаниеОповещения
//                        - Неопределено - описание процедуры, принимающей результат работы метода.
//
Процедура ПоказатьИнформациюФайлНеБылИзменен(ОбработчикРезультата)
	
	ПерсональныеНастройки = ПерсональныеНастройкиРаботыСФайлами();
	Если ПерсональныеНастройки.ПоказыватьИнформациюЧтоФайлНеБылИзменен Тогда
		ТекстНапоминания = НСтр("ru = 'Версия не была создана, т.к. файл не изменен. Комментарий не сохранен.'");
		Кнопки = РежимДиалогаВопрос.ОК;
		ПараметрыНапоминания = Новый Структура;
		ПараметрыНапоминания.Вставить("БлокироватьВесьИнтерфейс", Истина);
		ПараметрыНапоминания.Вставить("Картинка", БиблиотекаКартинок.Информация32);
		ПараметрыНапоминания.Вставить("ТекстФлажка",
			НСтр("ru = 'Больше не показывать это сообщение'"));
		ПараметрыНапоминания.Вставить("Заголовок",
			НСтр("ru = 'Информация'"));
		СтандартныеПодсистемыКлиент.ПоказатьВопросПользователю(
			ОбработчикРезультата, ТекстНапоминания, Кнопки, ПараметрыНапоминания);
	Иначе
		ВернутьРезультат(ОбработчикРезультата, Неопределено);
	КонецЕсли;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Загружает отредактированный файл в программу, снимает блокировку и рассылает оповещение.

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеСОповещениемЗавершение(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат = Истина Тогда
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ЗаконченоРедактирование"), ПараметрыВыполнения.ПараметрКоманды);
		ОповеститьОбИзменении(ПараметрыВыполнения.ПараметрКоманды);
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ДанныеФайлаИзменены"), ПараметрыВыполнения.ПараметрКоманды);
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ВерсияСохранена"), ПараметрыВыполнения.ПараметрКоманды);
		
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Результат);
	
КонецПроцедуры

// Сохраняет отредактированные файлы в ИБ и снимает блокировку.
//
// Параметры:
//   Параметры - см. ПараметрыОбновленияФайла.
//
Процедура ЗакончитьРедактированиеПоСсылкамСОповещением(Параметры) Экспорт
	
	Если ТипЗнч(Параметры.МассивФайлов) <> Тип("Массив") Тогда
		ВернутьРезультат(Параметры.ОбработчикРезультата, Неопределено);
		Возврат;
	КонецЕсли;
	
	Обработчик = Новый ОписаниеОповещения("ЗакончитьРедактированиеПоСсылкамПослеУстановкиРасширения", ЭтотОбъект, Параметры);
	ПоказатьВопросОбУстановкеРасширенияРаботыСФайлами(Обработчик);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗакончитьРедактированиеПоСсылкамПослеУстановкиРасширения(РасширениеУстановлено, ПараметрыВыполнения) Экспорт
	
	ПараметрыВыполнения.Вставить("ДанныеФайлов", Новый Массив);
	РаботаСФайламиСлужебныйВызовСервера.ПолучитьДанныеДляМассиваФайлов(ПараметрыВыполнения.МассивФайлов, ПараметрыВыполнения.ДанныеФайлов);
	
	// Завершение редактирования файлов.
	ДанныеФайлов = ПараметрыВыполнения.ДанныеФайлов; // Массив из см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла -
	Для Каждого ДанныеФайла Из ДанныеФайлов Цикл
		
		ПараметрыОбработчика = ПараметрыОбновленияФайла(Неопределено, ДанныеФайла.Ссылка, ПараметрыВыполнения.ИдентификаторФормы);
		ЗаполнитьЗначенияСвойств(ПараметрыОбработчика, ПараметрыВыполнения);
		ПараметрыОбработчика.Вставить("ДанныеФайла", Неопределено);
		ПараметрыОбработчика.ХранитьВерсии = ДанныеФайла.ХранитьВерсии;
		ПараметрыОбработчика.ФайлРедактируетТекущийПользователь = ДанныеФайла.ФайлРедактируетТекущийПользователь;
		ПараметрыОбработчика.Редактирует = ДанныеФайла.Редактирует;
		ПараметрыОбработчика.АвторТекущейВерсии = ДанныеФайла.Редактирует;
		ПараметрыОбработчика.Кодировка = ДанныеФайла.КодировкаТекущейВерсии;
		Если ПараметрыВыполнения.ВозможностьСоздаватьВерсииФайлов Тогда
			ПараметрыОбработчика.СоздатьНовуюВерсию = ПараметрыВыполнения.ХранитьВерсии;
		Иначе
			ПараметрыОбработчика.СоздатьНовуюВерсию = Ложь;
		КонецЕсли;
		ПараметрыОбработчика.ПрименитьКоВсем = Истина;
		
		Если РасширениеУстановлено Тогда
			ЗакончитьРедактированиеСРасширением(ПараметрыОбработчика);
		Иначе
			ЗакончитьРедактированиеБезРасширения(ПараметрыОбработчика);
		КонецЕсли;
	КонецЦикла;
	
	ПоказатьОповещениеПользователя(НСтр("ru = 'Завершить редактирование файлов'"),,
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Завершено редактирование файлов (%1 из %2).'"),
			ПараметрыВыполнения.ДанныеФайлов.Количество(),
			ПараметрыВыполнения.МассивФайлов.Количество()),
			БиблиотекаКартинок.Информация32);
	
	ОбработчикРезультата = Новый ОписаниеОповещения("ЗакончитьРедактированиеМассиваФайловСОповещениемЗавершение", ЭтотОбъект, ПараметрыВыполнения);
	ВернутьРезультат(ОбработчикРезультата, Истина);

КонецПроцедуры

Процедура ЗакончитьРедактированиеМассиваФайловСОповещениемЗавершение(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат = Истина Тогда
		
		Для Каждого ФайлСсылка Из ПараметрыВыполнения.МассивФайлов Цикл
			
			Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ЗаконченоРедактирование"), ФайлСсылка);
			ОповеститьОбИзменении(ФайлСсылка);
			Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ДанныеФайлаИзменены"), ФайлСсылка);
			Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ВерсияСохранена"), ФайлСсылка);
			
		КонецЦикла;
		
	КонецЕсли;
	
КонецПроцедуры

// Добавляет файлы перетаскиванием в список файлов.
//
// Параметры:
//  ВладелецФайла      - ЛюбаяСсылка - владелец файла.
//  ИдентификаторФормы - УникальныйИдентификатор формы.
//  МассивИменФайлов   - Массив из Строка - путей к файлам.
//
Процедура ДобавитьФайлыПеретаскиванием(Знач ВладелецФайла, Знач ИдентификаторФормы, Знач МассивИменФайлов) Экспорт
	
	ПрисоединенныеФайлыМассив = Новый Массив;
	ПоместитьВыбранныеФайлыВХранилище(
		МассивИменФайлов,
		ВладелецФайла,
		ПрисоединенныеФайлыМассив,
		ИдентификаторФормы);
	
	Если ПрисоединенныеФайлыМассив.Количество() = 1 Тогда
		ПрисоединенныйФайл = ПрисоединенныеФайлыМассив[0];
		
		ПоказатьОповещениеПользователя(
			НСтр("ru = 'Создание'"),
			ПолучитьНавигационнуюСсылку(ПрисоединенныйФайл),
			ПрисоединенныйФайл,
			БиблиотекаКартинок.Информация32);
		
		ПараметрыФормы = Новый Структура("ПрисоединенныйФайл, ЭтоНовый", ПрисоединенныйФайл, Истина);
		ОткрытьФорму("Обработка.РаботаСФайлами.Форма.ПрисоединенныйФайл", ПараметрыФормы, , ПрисоединенныйФайл);
	КонецЕсли;
	
	Если ПрисоединенныеФайлыМассив.Количество() > 0 Тогда
		ОповеститьОбИзменении(ПрисоединенныеФайлыМассив[0]);
		ОповеститьОбИзменении(ВладелецФайла);
		ПараметрыОповещенияЗаписиФайла = ПараметрыОповещенияЗаписиФайла();
		ПараметрыОповещенияЗаписиФайла.ЭтоНовый = Истина;
		ПараметрыОповещенияЗаписиФайла.Владелец = ВладелецФайла;
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла, ПрисоединенныеФайлыМассив);
	КонецЕсли;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Захватывает файл, открывает диалог редактирования и рассылает оповещение.

// Блокирует файл для редактирования и открывает его.
Процедура РедактироватьСОповещением(ОбработчикРезультата, ОбъектСсылка,
	УникальныйИдентификатор = Неопределено, РабочийКаталогВладельца = Неопределено) Экспорт
	
	Если ОбъектСсылка = Неопределено Тогда
		ВернутьРезультат(ОбработчикРезультата, Неопределено);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("ОбъектСсылка", ОбъектСсылка);
	Обработчик = Новый ОписаниеОповещения("РедактироватьСОповещениемЗавершение", ЭтотОбъект, ПараметрыВыполнения);
	РедактироватьФайлПоСсылке(Обработчик, ОбъектСсылка, УникальныйИдентификатор, РабочийКаталогВладельца);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура РедактироватьСОповещениемЗавершение(ФайлОтредактирован, ПараметрыВыполнения) Экспорт
	
	Если ФайлОтредактирован Тогда
		ОповеститьОбИзменении(ПараметрыВыполнения.ОбъектСсылка);
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ДанныеФайлаИзменены"), ПараметрыВыполнения.ОбъектСсылка);
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ФайлРедактировался"), ПараметрыВыполнения.ОбъектСсылка);
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Захватывает файл или несколько файлов и рассылает оповещение.

// Выполняет блокировку файла или нескольких файлов.
//
// Параметры:
//   ОбработчикРезультата - ОписаниеОповещения
//                        - Неопределено - описание процедуры, принимающей результат работы метода.
//   ПараметрКоманды - либо ссылка на файл, либо массив ссылок на файлы.
//   УникальныйИдентификатор.
//
Процедура ЗанятьСОповещением(ОбработчикРезультата, ПараметрКоманды, УникальныйИдентификатор = Неопределено) Экспорт
	
	Если ПараметрКоманды = Неопределено Тогда
		ВернутьРезультат(ОбработчикРезультата, Неопределено);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("ПараметрКоманды", ПараметрКоманды);
	Если ТипЗнч(ПараметрКоманды) = Тип("Массив") Тогда
		Обработчик = Новый ОписаниеОповещения("ЗанятьСОповещениемМассивФайловЗавершение", ЭтотОбъект, ПараметрыВыполнения);
		ЗанятьФайлыПоСсылкам(Обработчик, ПараметрКоманды);
	Иначе
		Обработчик = Новый ОписаниеОповещения("ЗанятьСОповещениемОдинФайлЗавершение", ЭтотОбъект, ПараметрыВыполнения);
		ЗанятьФайлПоСсылке(Обработчик, ПараметрКоманды, УникальныйИдентификатор)
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗанятьСОповещениемМассивФайловЗавершение(Результат, ПараметрыВыполнения) Экспорт
	
	ОповеститьОбИзменении(Тип("СправочникСсылка.Файлы"));
	Для Каждого ФайлСсылка Из ПараметрыВыполнения.ПараметрКоманды Цикл
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ДанныеФайлаИзменены"), ФайлСсылка);
		ОповеститьОбИзменении(ФайлСсылка);
	КонецЦикла;
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ЗанятьСОповещениемОдинФайлЗавершение(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат = Истина Тогда
		ОповеститьОбИзменении(ПараметрыВыполнения.ПараметрКоманды);
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ДанныеФайлаИзменены"), ПараметрыВыполнения.ПараметрКоманды);
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Снимает блокировку файла и рассылает оповещение.

// Освобождает занятый ранее файл.
//
// Параметры:
//   Параметры - см. ПараметрыОсвобожденияФайла.
//
Процедура ОсвободитьФайлСОповещением(Параметры) Экспорт
	
	Если Параметры.ОбъектСсылка = Неопределено Тогда
		ВернутьРезультат(Параметры.ОбработчикРезультата, Неопределено);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", Параметры.ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("ПараметрКоманды", Параметры.ОбъектСсылка);
	Если ТипЗнч(Параметры.ОбъектСсылка) = Тип("Массив") Тогда
		Обработчик = Новый ОписаниеОповещения("ОсвободитьФайлСОповещениемМассивФайловЗавершение", ЭтотОбъект, ПараметрыВыполнения);
		ОсвободитьФайлыПоСсылкам(Обработчик, Параметры.ОбъектСсылка);
	Иначе
		Обработчик = Новый ОписаниеОповещения("ОсвободитьФайлСОповещениемОдинФайлЗавершение", ЭтотОбъект, ПараметрыВыполнения);
		ПараметрыОсвобождения = ПараметрыОсвобожденияФайла(Обработчик, Параметры.ОбъектСсылка);
		ПараметрыОсвобождения.ХранитьВерсии = Параметры.ХранитьВерсии;
		ПараметрыОсвобождения.ФайлРедактируетТекущийПользователь = Параметры.ФайлРедактируетТекущийПользователь;
		ПараметрыОсвобождения.Редактирует = Параметры.Редактирует;
		ПараметрыОсвобождения.УникальныйИдентификатор = Параметры.УникальныйИдентификатор;
		ОсвободитьФайл(Параметры);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ОсвободитьФайлСОповещениемМассивФайловЗавершение(Результат, ПараметрыВыполнения) Экспорт
	
	ОповеститьОбИзменении(Тип("СправочникСсылка.Файлы"));
	Для Каждого ФайлСсылка Из ПараметрыВыполнения.ПараметрКоманды Цикл
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ДанныеФайлаИзменены"), ФайлСсылка);
	КонецЦикла;
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ОсвободитьФайлСОповещениемОдинФайлЗавершение(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат = Истина Тогда
		
		ОповеститьОбИзменении(ПараметрыВыполнения.ПараметрКоманды);
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ДанныеФайлаИзменены"), ПараметрыВыполнения.ПараметрКоманды);
		
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Открывает файл и рассылает оповещение.

// Открывает файл.
//
// Параметры:
//   ОбработчикРезультата - ОписаниеОповещения
//                        - Неопределено - описание процедуры, принимающей результат работы метода.
//   ДанныеФайла             - Структура
//   УникальныйИдентификатор - УникальныйИдентификатор - формы.
//
Процедура ОткрытьФайлСОповещением(ОбработчикРезультата, ДанныеФайла, УникальныйИдентификатор = Неопределено, ДляРедактирования = Истина) Экспорт
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("ДанныеФайла", ДанныеФайла);
	ПараметрыВыполнения.Вставить("ДляРедактирования", ДляРедактирования);
	ПараметрыВыполнения.Вставить("УникальныйИдентификатор", УникальныйИдентификатор);
	
	// Файл не содержит владельца, просто открываем его по ссылке из временного хранилища.
	Если НЕ ПараметрыВыполнения.ДанныеФайла.Свойство("Владелец") Или Не ЗначениеЗаполнено(ПараметрыВыполнения.ДанныеФайла.Владелец) Тогда
		ОписаниеОповещения = Новый ОписаниеОповещения("ОткрытьФайлРасширениеПредложено", РаботаСФайламиСлужебныйКлиент, ПараметрыВыполнения);
		ПоказатьВопросОбУстановкеРасширенияРаботыСФайлами(ОписаниеОповещения);
		Возврат;
	КонецЕсли;
	
	// Если Файл без файла, тогда открыть карточку.
	Если ПараметрыВыполнения.ДанныеФайла.Версия.Пустая() И ПараметрыВыполнения.ДанныеФайла.ХранитьВерсии Тогда
		Обработчик = Новый ОписаниеОповещения("ОткрытьФайлСОповещениемЗавершение", ЭтотОбъект, ПараметрыВыполнения);
		ПоказатьЗначение(Обработчик, ПараметрыВыполнения.ДанныеФайла.Ссылка);
		Возврат;
	КонецЕсли;
	
	Обработчик = Новый ОписаниеОповещения("ОткрытьФайлСОповещениемПослеУстановкиРасширения", ЭтотОбъект, ПараметрыВыполнения);
	ПоказатьВопросОбУстановкеРасширенияРаботыСФайлами(Обработчик);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ОткрытьФайлСОповещениемПослеУстановкиРасширения(РасширениеУстановлено, ПараметрыВыполнения) Экспорт
	
	Если РасширениеРаботыСФайламиПодключено() Тогда
		Обработчик = Новый ОписаниеОповещения("ОткрытьФайлСОповещениемСРасширениемПослеПолученияВерсииВРабочийКаталог", ЭтотОбъект, ПараметрыВыполнения);
		ПолучитьФайлВерсииВРабочийКаталог(
			Обработчик,
			ПараметрыВыполнения.ДанныеФайла,
			"",
			ПараметрыВыполнения.УникальныйИдентификатор,
			Новый Структура("ОткрытьФайл", Истина));
	Иначе
		ЗаполнитьВременныйИдентификаторФормы(ПараметрыВыполнения.УникальныйИдентификатор, ПараметрыВыполнения);
		
		Обработчик = Новый ОписаниеОповещения("ОткрытьФайлСОповещениемЗавершение", ЭтотОбъект, ПараметрыВыполнения);
		ОткрытьФайлБезРасширения(Обработчик, ПараметрыВыполнения.ДанныеФайла, ПараметрыВыполнения.УникальныйИдентификатор);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ОткрытьФайлСОповещениемСРасширениемПослеПолученияВерсииВРабочийКаталог(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат.ФайлПолучен = Истина Тогда
		ФайлНаДиске = Новый Файл(Результат.ПолноеИмяФайла);
		ФайлНаДиске.УстановитьТолькоЧтение(Не ПараметрыВыполнения.ДляРедактирования);
		УникальныйИдентификатор = ?(ПараметрыВыполнения.Свойство("УникальныйИдентификатор"),
			ПараметрыВыполнения.УникальныйИдентификатор, Неопределено);
		ОткрытьФайлПриложением(ПараметрыВыполнения.ДанныеФайла, Результат.ПолноеИмяФайла, УникальныйИдентификатор);
	КонецЕсли;
	
	ОткрытьФайлСОповещениемЗавершение(Результат.ФайлПолучен = Истина, ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения   - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//
Процедура ОткрытьФайлСОповещениемЗавершение(Результат, ПараметрыВыполнения) Экспорт
	
	ОчиститьВременныйИдентификаторФормы(ПараметрыВыполнения);
	
	Если Результат <> Истина Тогда
		Возврат;
	КонецЕсли;
	
	ПараметрыОповещения = Новый Структура;
	ПараметрыОповещения.Вставить("Событие", "ФайлОткрыт");
	Оповестить("ФайлОткрыт", ПараметрыОповещения, ПараметрыВыполнения.ДанныеФайла.Ссылка);
	
КонецПроцедуры


Процедура ОткрытьФайлБезРасширения(Оповещение, ДанныеФайла, ИдентификаторФормы,
		СПредупреждением = Истина, СохранятьСРасшифровкой = Истина, РасширениеДляЗашифрованныхФайлов = "")
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение",             Оповещение);
	Контекст.Вставить("ДанныеФайла",            ДанныеФайла);
	Контекст.Вставить("ИдентификаторФормы",     ИдентификаторФормы);
	Контекст.Вставить("СПредупреждением",       СПредупреждением);
	Контекст.Вставить("СохранятьСРасшифровкой", СохранятьСРасшифровкой);
	Контекст.Вставить("РасширениеДляЗашифрованныхФайлов", РасширениеДляЗашифрованныхФайлов);
	
	Если Контекст.СохранятьСРасшифровкой
		И ДанныеФайла.Зашифрован Тогда
		
		Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
			ВыполнитьОбработкуОповещения(Контекст.Оповещение, Ложь);
			Возврат;
		КонецЕсли;
		
		СтруктураВозврата = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИДвоичныеДанные(
			ДанныеФайла.Версия,, ИдентификаторФормы);
		
		ОписаниеДанных = Новый Структура;
		ОписаниеДанных.Вставить("Операция",              НСтр("ru = 'Расшифровка файла'"));
		ОписаниеДанных.Вставить("ЗаголовокДанных",       НСтр("ru = 'Файл'"));
		ОписаниеДанных.Вставить("Данные",                СтруктураВозврата.ДвоичныеДанные);
		ОписаниеДанных.Вставить("Представление",         ДанныеФайла.Ссылка);
		ОписаниеДанных.Вставить("СертификатыШифрования", ДанныеФайла.Ссылка);
		ОписаниеДанных.Вставить("СообщитьОЗавершении",   Ложь);
		
		ОбработчикПродолжения = Новый ОписаниеОповещения(
			"ОткрытьФайлБезРасширенияПослеРасшифровки", ЭтотОбъект, Контекст);
		
		МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
		МодульЭлектроннаяПодписьКлиент.Расшифровать(ОписаниеДанных, , ОбработчикПродолжения);
		Возврат;
		
	КонецЕсли;
	
	Контекст.Вставить("АдресФайла", ДанныеФайла.СсылкаНаДвоичныеДанныеФайла);
	
	ОткрытьФайлБезРасширенияНапоминание(Контекст);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ОткрытьФайлБезРасширенияПослеРасшифровки(ОписаниеДанных, Контекст) Экспорт
	
	Если Не ОписаниеДанных.Успех Тогда
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Ложь);
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(ОписаниеДанных.РасшифрованныеДанные) = Тип("ДвоичныеДанные") Тогда
		АдресФайла = ПоместитьВоВременноеХранилище(ОписаниеДанных.РасшифрованныеДанные,
			Контекст.ИдентификаторФормы);
	Иначе
		АдресФайла = ОписаниеДанных.РасшифрованныеДанные;
	КонецЕсли;
	
	Контекст.Вставить("АдресФайла", АдресФайла);
	
	ОткрытьФайлБезРасширенияНапоминание(Контекст);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ОткрытьФайлБезРасширенияНапоминание(Контекст)
	
	Если Контекст.СПредупреждением
		И Контекст.ДанныеФайла.ФайлРедактируетТекущийПользователь Тогда
		
		ВывестиНапоминаниеПриРедактировании(Новый ОписаниеОповещения(
		"ОткрытьФайлБезРасширенияПередачаФайла", ЭтотОбъект, Контекст));
	Иначе
		ОткрытьФайлБезРасширенияПередачаФайла(Истина, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ОткрытьФайлБезРасширенияПередачаФайла(Результат, Контекст) Экспорт
	
	Если (ТипЗнч(Результат) = Тип("Структура") И Результат.Значение = "Отмена") Или Результат = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Если ТипЗнч(Результат) = Тип("Структура") И Результат.Свойство("БольшеНеЗадаватьЭтотВопрос") И Результат.БольшеНеЗадаватьЭтотВопрос Тогда
		РаботаСФайламиСлужебныйВызовСервера.ПоказыватьПодсказкиПриРедактированииФайлов(Ложь);
	КонецЕсли;
	
	Если Не Контекст.СохранятьСРасшифровкой
		И Контекст.ДанныеФайла.Зашифрован
		И ЗначениеЗаполнено(Контекст.РасширениеДляЗашифрованныхФайлов) Тогда
		
		Расширение = Контекст.РасширениеДляЗашифрованныхФайлов;
	Иначе
		Расширение = Контекст.ДанныеФайла.Расширение;
	КонецЕсли;
	
	ИмяФайла = ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(
		Контекст.ДанныеФайла.ПолноеНаименованиеВерсии, Расширение);
	
	ПолучитьФайл(Контекст.АдресФайла, ИмяФайла, Истина);
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Истина);
	
КонецПроцедуры

// Заполняет временный идентификатор формы для случаев, когда не требуется
// возвращать данные во временном хранилище в вызывающий код, например,
// как в процедурах Открыть, ОткрытьКаталогФайла в общем модуле РаботаСФайламиКлиент.
//
Процедура ЗаполнитьВременныйИдентификаторФормы(ИдентификаторФормы, ПараметрыВыполнения)
	
	Если ЗначениеЗаполнено(ИдентификаторФормы) Тогда
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.Вставить("ВременнаяФорма", ПолучитьФорму("Обработка.РаботаСФайлами.Форма.ФормаВопроса")); // АПК:65
	ИдентификаторФормы = ПараметрыВыполнения.ВременнаяФорма.УникальныйИдентификатор;
	СтандартныеПодсистемыКлиент.УстановитьХранениеФормы(ПараметрыВыполнения.ВременнаяФорма, Истина);
	
КонецПроцедуры

// Отменяет хранение временного идентификатора, заполненного ранее.
Процедура ОчиститьВременныйИдентификаторФормы(ПараметрыВыполнения)
	
	Если ПараметрыВыполнения.Свойство("ВременнаяФорма") Тогда
		СтандартныеПодсистемыКлиент.УстановитьХранениеФормы(ПараметрыВыполнения.ВременнаяФорма, Ложь);
	КонецЕсли;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Загружает файл в программу и рассылает оповещение.

// Продолжение процедуры (см. выше).
Процедура СохранитьИзмененияФайлаСОповещениемЗавершение(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат = Истина Тогда
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ДанныеФайлаИзменены"), ПараметрыВыполнения.ПараметрКоманды);
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ВерсияСохранена"), ПараметрыВыполнения.ПараметрКоманды);
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Результат);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Показывает диалог выбора файла, загружает выбранный файл в программу как версию и рассылает оповещение.

// Выбирает файл и создает из него новую версию.
Процедура ОбновитьИзФайлаНаДискеСОповещением(
	ОбработчикРезультата,
	ДанныеФайла,
	ИдентификаторФормы,
	ПараметрыДобавленияФайла = Неопределено) Экспорт
	
	Если Не РасширениеРаботыСФайламиПодключено() Тогда
		ПоказатьПредупреждениеОНеобходимостиРасширенияРаботыСФайлами(ОбработчикРезультата);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("ДанныеФайла", ДанныеФайла);
	Обработчик = Новый ОписаниеОповещения("ОбновитьИзФайлаНаДискеСОповещениемЗавершение", ЭтотОбъект, ПараметрыВыполнения);
	ОбновитьИзФайлаНаДиске(Обработчик, ДанныеФайла, ИдентификаторФормы, ПараметрыДобавленияФайла);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения   - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//
Процедура ОбновитьИзФайлаНаДискеСОповещениемЗавершение(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат = Истина Тогда
		ОповеститьОбИзменении(ПараметрыВыполнения.ДанныеФайла.Ссылка);
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ДанныеФайлаИзменены"), ПараметрыВыполнения.ДанныеФайла.Ссылка);
		Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ВерсияСохранена"), ПараметрыВыполнения.ДанныеФайла.Ссылка);
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Шифрование файла.

// Зашифровать файл.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//  УникальныйИдентификатор - УникальныйИдентификатор - идентификатор формы.
//
Процедура Зашифровать(ОбработчикРезультата, ДанныеФайла, УникальныйИдентификатор) Экспорт
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("ДанныеФайла", ДанныеФайла);
	ПараметрыВыполнения.Вставить("УникальныйИдентификатор", УникальныйИдентификатор);
	ПараметрыВыполнения.Вставить("Успех", Ложь);
	ПараметрыВыполнения.Вставить("МассивДанныхДляЗанесенияВБазу", Новый Массив);
	ПараметрыВыполнения.Вставить("МассивОтпечатков", Новый Массив);
	
	Если ПараметрыВыполнения.ДанныеФайла.Зашифрован Тогда
		ТекстПредупреждения = НСтр("ru = 'Файл ""%1"" уже зашифрован.'");
		ТекстПредупреждения = СтрЗаменить(ТекстПредупреждения, "%1", Строка(ПараметрыВыполнения.ДанныеФайла.Ссылка));
		ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, ТекстПредупреждения, ПараметрыВыполнения);
		Возврат;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ПараметрыВыполнения.ДанныеФайла.Редактирует) Тогда
		ТекстПредупреждения = НСтр("ru = 'Нельзя зашифровать занятый файл.'");
		ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, ТекстПредупреждения, ПараметрыВыполнения);
		Возврат;
	КонецЕсли;
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		Возврат;
	КонецЕсли;
	
	// Не нужно ПредложитьУстановкуРасширенияРаботыСФайлами(), т.к. все делается в памяти через ДвоичныеДанные.
	
	МассивВерсий = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИНавигационнаяСсылкаВсехВерсийФайла(ПараметрыВыполнения.ДанныеФайла.Ссылка,
		ПараметрыВыполнения.УникальныйИдентификатор);
	
	Если МассивВерсий.Количество() = 0 Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Ложь);
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения.МассивДанныхДляЗанесенияВБазу = Новый Массив;
	
	ПредставлениеФайла = Строка(ПараметрыВыполнения.ДанныеФайла.Ссылка);
	Если ПараметрыВыполнения.ДанныеФайла.КоличествоВерсий > 1 Тогда
		ПредставлениеФайла = ПредставлениеФайла + " (" + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Версий: %1'"), ПараметрыВыполнения.ДанныеФайла.КоличествоВерсий) + ")";
	КонецЕсли;
	СписокПредставлений = Новый СписокЗначений;
	СписокПредставлений.Добавить(ПараметрыВыполнения.ДанныеФайла.Ссылка, ПредставлениеФайла);
	
	НаборДанных = Новый Массив;
	
	Для каждого СвойстваВерсии Из МассивВерсий Цикл
		
		ТекущиеПараметрыВыполнения = Новый Структура;
		ТекущиеПараметрыВыполнения.Вставить("ПараметрыВыполнения", ПараметрыВыполнения);
		ТекущиеПараметрыВыполнения.Вставить("ВерсияСсылка", СвойстваВерсии.ВерсияСсылка);
		ТекущиеПараметрыВыполнения.Вставить("АдресФайла",   СвойстваВерсии.НавигационнаяСсылкаВерсии);
		
		ЭлементДанных = Новый Структура;
		ЭлементДанных.Вставить("Данные", СвойстваВерсии.НавигационнаяСсылкаВерсии);
		
		ЭлементДанных.Вставить("РазмещениеРезультата", Новый ОписаниеОповещения(
			"ПриПолученииЗашифрованныхДанных", ЭтотОбъект, ТекущиеПараметрыВыполнения));
		
		НаборДанных.Добавить(ЭлементДанных);
	КонецЦикла;
	
	ОписаниеДанных = Новый Структура;
	ОписаниеДанных.Вставить("Операция",            НСтр("ru = 'Шифрование файла'"));
	ОписаниеДанных.Вставить("ЗаголовокДанных",     НСтр("ru = 'Файл'"));
	ОписаниеДанных.Вставить("НаборДанных",         НаборДанных);
	ОписаниеДанных.Вставить("ПредставлениеНабора", НСтр("ru = 'Файлы (%1)'"));
	ОписаниеДанных.Вставить("СписокПредставлений", СписокПредставлений);
	ОписаниеДанных.Вставить("СообщитьОЗавершении", Ложь);
	
	ОбработчикПродолжения = Новый ОписаниеОповещения("ПослеШифрованияФайла", ЭтотОбъект, ПараметрыВыполнения);
	
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	МодульЭлектроннаяПодписьКлиент.Зашифровать(ОписаниеДанных, , ОбработчикПродолжения);
	
КонецПроцедуры

// Параметры:
//   ТекущиеПараметрыВыполнения - Структура:
//     * ПараметрыВыполнения - Структура:
//       ** МассивДанныхДляЗанесенияВБазу - Массив
//
Процедура ПриПолученииЗашифрованныхДанных(Параметры, ТекущиеПараметрыВыполнения) Экспорт
	
	ПараметрыВыполнения = ТекущиеПараметрыВыполнения.ПараметрыВыполнения;
	
	ЗашифрованныеДанные = Параметры.ОписаниеДанных.ТекущийЭлементНабораДанных.ЗашифрованныеДанные;
	Если ТипЗнч(ЗашифрованныеДанные) = Тип("ДвоичныеДанные") Тогда
		АдресВременногоХранилища = ПоместитьВоВременноеХранилище(ЗашифрованныеДанные,
			ПараметрыВыполнения.УникальныйИдентификатор);
	Иначе
		АдресВременногоХранилища = ЗашифрованныеДанные;
	КонецЕсли;
	
	ДанныеДляЗаписиНаСервере = Новый Структура;
	ДанныеДляЗаписиНаСервере.Вставить("АдресВременногоХранилища", АдресВременногоХранилища);
	ДанныеДляЗаписиНаСервере.Вставить("ВерсияСсылка", ТекущиеПараметрыВыполнения.ВерсияСсылка);
	ДанныеДляЗаписиНаСервере.Вставить("АдресФайла",   ТекущиеПараметрыВыполнения.АдресФайла);
	ДанныеДляЗаписиНаСервере.Вставить("АдресВременногоХранилищаТекста", "");
	
	ПараметрыВыполнения.МассивДанныхДляЗанесенияВБазу.Добавить(ДанныеДляЗаписиНаСервере);
	
	ВыполнитьОбработкуОповещения(Параметры.Оповещение, Новый Структура);
	
КонецПроцедуры

// Завершение процедуры Зашифровать. Вызывается из подсистемы ЭлектроннаяПодпись.
Процедура ПослеШифрованияФайла(ОписаниеДанных, ПараметрыВыполнения) Экспорт
	
	ПараметрыВыполнения.Успех = ОписаниеДанных.Успех;
	
	Если ОписаниеДанных.Успех Тогда
		Если ТипЗнч(ОписаниеДанных.СертификатыШифрования) = Тип("Строка") Тогда
			ПараметрыВыполнения.Вставить("МассивОтпечатков", ПолучитьИзВременногоХранилища(
				ОписаниеДанных.СертификатыШифрования));
		Иначе
			ПараметрыВыполнения.Вставить("МассивОтпечатков", ОписаниеДанных.СертификатыШифрования);
		КонецЕсли;
		ОповеститьОбИзмененииФайла(ПараметрыВыполнения.ДанныеФайла);
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Расшифровка файла.

// Расшифровка файла.
//
// Параметры:
//  ОбработчикРезультата - ОписаниеОповещения
//                       - Неопределено - описание процедуры, принимающей результат работы метода.
//  ФайлСсылка  - СправочникСсылка.Файлы - файл.
//  УникальныйИдентификатор - УникальныйИдентификатор - идентификатор формы.
//  ДанныеФайла  - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//
Процедура Расшифровать(ОбработчикРезультата, ФайлСсылка, УникальныйИдентификатор, ДанныеФайла) Экспорт
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		Возврат;
	КонецЕсли;
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("ФайлСсылка", ФайлСсылка);
	ПараметрыВыполнения.Вставить("УникальныйИдентификатор", УникальныйИдентификатор);
	ПараметрыВыполнения.Вставить("ДанныеФайла", ДанныеФайла);
	ПараметрыВыполнения.Вставить("Успех", Ложь);
	ПараметрыВыполнения.Вставить("МассивДанныхДляЗанесенияВБазу", Новый Массив);
	
	// Не нужно ПредложитьУстановкуРасширенияРаботыСФайлами(), т.к. все делается в памяти через ДвоичныеДанные.
	
	МассивВерсий = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИНавигационнаяСсылкаВсехВерсийФайла(
		ПараметрыВыполнения.ФайлСсылка, ПараметрыВыполнения.УникальныйИдентификатор);
	
	ПараметрыВыполнения.МассивДанныхДляЗанесенияВБазу = Новый Массив;
	
	ПараметрыВыполнения.Вставить("ИзвлекатьТекстыФайловНаСервере",
		ОбщиеНастройкиРаботыСФайлами().ИзвлекатьТекстыФайловНаСервере);
	
	ПредставлениеФайла = Строка(ДанныеФайла.Ссылка);
	Если ДанныеФайла.КоличествоВерсий > 1 Тогда
		ПредставлениеФайла = ПредставлениеФайла + " (" + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Версий: %1'"), ДанныеФайла.КоличествоВерсий) + ")";
	КонецЕсли;
	СписокПредставлений = Новый СписокЗначений;
	СписокПредставлений.Добавить(ДанныеФайла.Ссылка, ПредставлениеФайла);
	
	СертификатыШифрования = Новый Массив;
	СертификатыШифрования.Добавить(ДанныеФайла.Ссылка);
	
	НаборДанных = Новый Массив;
	
	Для каждого СвойстваВерсии Из МассивВерсий Цикл
		
		ТекущиеПараметрыВыполнения = Новый Структура;
		ТекущиеПараметрыВыполнения.Вставить("ПараметрыВыполнения", ПараметрыВыполнения);
		ТекущиеПараметрыВыполнения.Вставить("ВерсияСсылка", СвойстваВерсии.ВерсияСсылка);
		ТекущиеПараметрыВыполнения.Вставить("АдресФайла",   СвойстваВерсии.НавигационнаяСсылкаВерсии);
		
		ЭлементДанных = Новый Структура;
		ЭлементДанных.Вставить("Данные", СвойстваВерсии.НавигационнаяСсылкаВерсии);
		
		ЭлементДанных.Вставить("РазмещениеРезультата", Новый ОписаниеОповещения(
			"ПриПолученииРасшифрованныхДанных", ЭтотОбъект, ТекущиеПараметрыВыполнения));
		
		НаборДанных.Добавить(ЭлементДанных);
	КонецЦикла;
	
	ОписаниеДанных = Новый Структура;
	ОписаниеДанных.Вставить("Операция",              НСтр("ru = 'Расшифровка файла'"));
	ОписаниеДанных.Вставить("ЗаголовокДанных",       НСтр("ru = 'Файл'"));
	ОписаниеДанных.Вставить("НаборДанных",           НаборДанных);
	ОписаниеДанных.Вставить("ПредставлениеНабора",   НСтр("ru = 'Файлы (%1)'"));
	ОписаниеДанных.Вставить("СписокПредставлений",   СписокПредставлений);
	ОписаниеДанных.Вставить("СертификатыШифрования", СертификатыШифрования);
	ОписаниеДанных.Вставить("СообщитьОЗавершении",   Ложь);
	
	ОбработчикПродолжения = Новый ОписаниеОповещения("ПослеРасшифровкиФайла", ЭтотОбъект, ПараметрыВыполнения);
	
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	МодульЭлектроннаяПодписьКлиент.Расшифровать(ОписаниеДанных, , ОбработчикПродолжения);
	
КонецПроцедуры

// Параметры:
//   ТекущиеПараметрыВыполнения - Структура:
//     * ПараметрыВыполнения - Структура:
//       ** ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//       ** МассивДанныхДляЗанесенияВБазу - Массив
//
Процедура ПриПолученииРасшифрованныхДанных(Параметры, ТекущиеПараметрыВыполнения) Экспорт
	
	ПараметрыВыполнения = ТекущиеПараметрыВыполнения.ПараметрыВыполнения;
	
	РасшифрованныеДанные = Параметры.ОписаниеДанных.ТекущийЭлементНабораДанных.РасшифрованныеДанные;
	Если ТипЗнч(РасшифрованныеДанные) = Тип("ДвоичныеДанные") Тогда
		АдресВременногоХранилища = ПоместитьВоВременноеХранилище(РасшифрованныеДанные,
			ПараметрыВыполнения.УникальныйИдентификатор);
		#Если Не ВебКлиент Тогда
			ДвоичныеДанныеРасшифрованные = РасшифрованныеДанные;
		#КонецЕсли
	Иначе
		АдресВременногоХранилища = РасшифрованныеДанные;
		#Если Не ВебКлиент Тогда
			ДвоичныеДанныеРасшифрованные = ПолучитьИзВременногоХранилища(АдресВременногоХранилища);
		#КонецЕсли
	КонецЕсли;
	
	АдресВременногоХранилищаТекста = "";
	#Если Не ВебКлиент Тогда
		Если Не ПараметрыВыполнения.ИзвлекатьТекстыФайловНаСервере Тогда
			ПолныйПутьКФайлу = ПолучитьИмяВременногоФайла(ПараметрыВыполнения.ДанныеФайла.Расширение);
			ДвоичныеДанныеРасшифрованные.Записать(ПолныйПутьКФайлу);
			
			АдресВременногоХранилищаТекста = ИзвлечьТекстВоВременноеХранилище(ПолныйПутьКФайлу, ПараметрыВыполнения.УникальныйИдентификатор);
			Попытка
				УдалитьФайлы(ПолныйПутьКФайлу);
			Исключение
				ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
					"Предупреждение", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()),, Истина);
			КонецПопытки;	
		КонецЕсли;
	#КонецЕсли
	
	ДанныеДляЗаписиНаСервере = Новый Структура;
	ДанныеДляЗаписиНаСервере.Вставить("АдресВременногоХранилища", АдресВременногоХранилища);
	ДанныеДляЗаписиНаСервере.Вставить("ВерсияСсылка", ТекущиеПараметрыВыполнения.ВерсияСсылка);
	ДанныеДляЗаписиНаСервере.Вставить("АдресФайла",   ТекущиеПараметрыВыполнения.АдресФайла);
	ДанныеДляЗаписиНаСервере.Вставить("АдресВременногоХранилищаТекста", АдресВременногоХранилищаТекста);
	ПараметрыВыполнения.МассивДанныхДляЗанесенияВБазу.Добавить(ДанныеДляЗаписиНаСервере);
	
	ВыполнитьОбработкуОповещения(Параметры.Оповещение, Новый Структура);
	
КонецПроцедуры

// Завершение процедуры Расшифровать. Вызывается из подсистемы ЭлектроннаяПодпись.
Процедура ПослеРасшифровкиФайла(ОписаниеДанных, ПараметрыВыполнения) Экспорт
	
	ПараметрыВыполнения.Успех = ОписаниеДанных.Успех;
	
	Если ОписаниеДанных.Успех Тогда
		ОповеститьОбИзмененииФайла(ПараметрыВыполнения.ДанныеФайла);
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, ПараметрыВыполнения);
	
КонецПроцедуры

// Продолжение процедуры ПроверитьПодписи. Вызывается из подсистемы ЭлектроннаяПодпись.
Процедура ПослеРасшифровкиФайлаПриПроверкеПодписи(ОписаниеДанных, ДополнительныеПараметры) Экспорт
	
	Если Не ОписаниеДанных.Успех Тогда
		Возврат;
	КонецЕсли;
	
	ПроверитьПодписиПослеПодготовкиДанных(ОписаниеДанных.РасшифрованныеДанные, ДополнительныеПараметры);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Продолжения асинхронных процедур.

////////////////////////////////////////////////////////////////////////////////
// Создает новый файл.

// Создает новый файл интерактивно с вызовом диалога выбора режима создания Файла.
//
// Параметры:
//   см. РаботаСФайламиКлиент.ДобавитьФайл().
//
Процедура ДобавитьФайл(
	ОбработчикРезультата,
	ВладелецФайла,
	ФормаВладелец,
	РежимСоздания = 1,
	ПараметрыДобавления = Неопределено) Экспорт
	
	ПараметрыВыполнения = Новый Структура;
	Если ПараметрыДобавления = Неопределено
		Или ТипЗнч(ПараметрыДобавления) = Тип("Булево") Тогда
		
		ПараметрыВыполнения.Вставить("МаксимальныйРазмер", 0);
		ПараметрыВыполнения.Вставить("ФильтрДиалогаВыбора",  СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Все файлы (%1)|%1'"), ПолучитьМаскуВсеФайлы()));
		ПараметрыВыполнения.Вставить("НеОткрыватьКарточкуПослеСозданияИзФайла", ?(ПараметрыДобавления = Неопределено, Ложь, ПараметрыДобавления));
		
	Иначе
		ПараметрыВыполнения.Вставить("МаксимальныйРазмер", ПараметрыДобавления.МаксимальныйРазмер);
		ПараметрыВыполнения.Вставить("ФильтрДиалогаВыбора", ПараметрыДобавления.ФильтрДиалогаВыбора);
		ПараметрыВыполнения.Вставить("НеОткрыватьКарточкуПослеСозданияИзФайла", ПараметрыДобавления.НеОткрыватьКарточку);
	КонецЕсли;
	
	ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	ПараметрыВыполнения.Вставить("ВладелецФайла", ВладелецФайла);
	ПараметрыВыполнения.Вставить("ФормаВладелец", ФормаВладелец);
	ПараметрыВыполнения.Вставить("ЭтоФайл", Истина);
	
	Обработчик = Новый ОписаниеОповещения("ДобавитьПослеВыбораРежимаСоздания", ЭтотОбъект, ПараметрыВыполнения);
	
	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("РежимСоздания", РежимСоздания);
	
	Контекст = Новый Структура;
	Контекст.Вставить("ПараметрыФормы", ПараметрыФормы);
	Контекст.Вставить("Обработчик", Обработчик);
	
	ПараметрыФормы.Вставить("ДоступнаКомандаСканировать", ДоступноСканирование());
	
	ОткрытьФорму("Справочник.Файлы.Форма.ФормаНового", ПараметрыФормы, , , , , Контекст.Обработчик);
	
КонецПроцедуры

Процедура ДобавитьФайлИзФайловойСистемы(ВладелецФайла, ФормаВладелец) Экспорт
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата",                    Неопределено);
	ПараметрыВыполнения.Вставить("ВладелецФайла",                           ВладелецФайла);
	ПараметрыВыполнения.Вставить("ФормаВладелец",                           ФормаВладелец);
	ПараметрыВыполнения.Вставить("ЭтоФайл",                                 Истина);
	
	ДобавитьПослеВыбораРежимаСоздания(2, ПараметрыВыполнения);
	
КонецПроцедуры

// Создает новый файл интерактивно указанным образом.
//
// Параметры:
//   РежимСоздания - Число - режим создания файла.
//       1 - из шаблона (копированием другого файла),
//       2 - с компьютера (из файловой системы),
//       3 - со сканера.
//   ПараметрыВыполнения - Структура - типы значений и описания см. в РаботаСФайламиКлиент.ДобавитьФайл().
//       * ОбработчикРезультата.
//       * ВладелецФайла.
//       * ФормаВладелец
//       * НеОткрыватьКарточкуПослеСозданияИзФайла.
//
Процедура ДобавитьПослеВыбораРежимаСоздания(РежимСоздания, ПараметрыВыполнения) Экспорт
	
	ПараметрыВыполнения.Вставить("НеОткрыватьКарточкуПослеСозданияИзФайла", Истина);
	
	Если РежимСоздания = 1 Тогда // Скопировать другой файла.
		ДобавитьНаОсновеШаблона(ПараметрыВыполнения);
	ИначеЕсли РежимСоздания = 2 Тогда // Загрузить из файловой системы.
		Если РасширениеРаботыСФайламиПодключено() Тогда
			ДобавитьИзФайловойСистемыСРасширением(ПараметрыВыполнения);
		Иначе
			ДобавитьИзФайловойСистемыБезРасширения(ПараметрыВыполнения);
		КонецЕсли;
	ИначеЕсли РежимСоздания = 3 Тогда // Считать со сканера.
		ПараметрыДобавления = РаботаСФайламиКлиент.ПараметрыДобавленияСоСканера();
		ЗаполнитьЗначенияСвойств(ПараметрыДобавления, ПараметрыВыполнения);
		ДобавитьСоСканера(ПараметрыДобавления);
	Иначе
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ДобавитьНаОсновеШаблона(ПараметрыВыполнения) Экспорт
	
	// Скопировать из файла шаблона.
	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("ВыборШаблона", Истина);
	ПараметрыФормы.Вставить("ТекущаяСтрока", ПредопределенноеЗначение("Справочник.ПапкиФайлов.Шаблоны"));
	Обработчик = Новый ОписаниеОповещения("ДобавитьНаОсновеШаблонаПослеВыбораШаблона", ЭтотОбъект, ПараметрыВыполнения);
	РежимОткрытия = РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс;
	ОткрытьФорму("Справочник.Файлы.Форма.ФормаВыбора", ПараметрыФормы, , , , , Обработчик, РежимОткрытия);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ДобавитьНаОсновеШаблонаПослеВыбораШаблона(Результат, ПараметрыВыполнения) Экспорт
	
	Если Результат = Неопределено Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
		Возврат;
	КонецЕсли;
	
	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("РежимСоздания", "ИзШаблона");
	ПараметрыФормы.Вставить("ИмяСправочникаХранилищаФайлов",
		?(ПараметрыВыполнения.Свойство("ИмяСправочникаХранилищаФайлов"),
		ПараметрыВыполнения.ИмяСправочникаХранилищаФайлов, 
		РаботаСФайламиСлужебныйВызовСервера.ИмяСправочникаХраненияФайлов(ПараметрыВыполнения.ВладелецФайла)));
		
	ОписаниеОповещенияОЗакрытии = ОбработчикЗавершения(ПараметрыВыполнения.ОбработчикРезультата);
	РаботаСФайламиКлиент.СкопироватьФайл(ПараметрыВыполнения.ВладелецФайла, Результат, ПараметрыФормы, ОписаниеОповещенияОЗакрытии); 
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ДобавитьИзФайловойСистемыБезРасширения(ПараметрыВыполнения)
	
	// Загрузить из файловой системы без расширения для работы с 1С:Предприятием (веб-клиент).
	ДиалогВыбора = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
	Если ПараметрыВыполнения.Свойство("ФильтрДиалогаВыбора") Тогда
		ДиалогВыбора.Фильтр = ПараметрыВыполнения.ФильтрДиалогаВыбора;
	КонецЕсли;
	
	Обработчик = Новый ОписаниеОповещения("ДобавитьИзФайловойСистемыБезРасширенияПослеЗагрузкиФайла", ЭтотОбъект, ПараметрыВыполнения);
	НачатьПомещениеФайла(Обработчик, , ДиалогВыбора, , ПараметрыВыполнения.ФормаВладелец.УникальныйИдентификатор);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ДобавитьИзФайловойСистемыБезРасширенияПослеЗагрузкиФайла(Помещен, Адрес, ВыбранноеИмяФайла, ПараметрыВыполнения) Экспорт
	
	Если Не Помещен Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
		Возврат;
	КонецЕсли;
	
	Результат = Новый Структура;
	Результат.Вставить("ФайлДобавлен", Ложь);
	Результат.Вставить("ФайлСсылка",   Неопределено);
	Результат.Вставить("ТекстОшибки",  "");
	
	СтруктураПути = ОбщегоНазначенияКлиентСервер.РазложитьПолноеИмяФайла(ВыбранноеИмяФайла);
	Если ПустаяСтрока(СтруктураПути.Расширение) Тогда
		ТекстВопроса = НСтр("ru = 'Укажите файл с расширением.'");
		Кнопки = Новый СписокЗначений;
		Кнопки.Добавить(КодВозвратаДиалога.Повторить, НСтр("ru = 'Выбрать другой файл'"));
		Кнопки.Добавить(КодВозвратаДиалога.Отмена);
		Обработчик = Новый ОписаниеОповещения("ДобавитьИзФайловойСистемыБезРасширенияПослеОтветаНаВопросПовторить", ЭтотОбъект, ПараметрыВыполнения);
		ПоказатьВопрос(Обработчик, ТекстВопроса, Кнопки);
		Возврат;
	КонецЕсли;
	
	Если ПараметрыВыполнения.Свойство("МаксимальныйРазмер")
		И ПараметрыВыполнения.МаксимальныйРазмер > 0 Тогда
		
		РазмерФайла = ПолучитьИзВременногоХранилища(Адрес).Размер();
		Если РазмерФайла > ПараметрыВыполнения.МаксимальныйРазмер*1024*1024 Тогда
			
			ТекстОшибки = НСтр("ru = 'Размер файла превышает %1 Мб.'");
			Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, 
				ПараметрыВыполнения.МаксимальныйРазмер);
			ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, Результат.ТекстОшибки, Неопределено);
			Возврат;
			
		КонецЕсли;
		
	КонецЕсли;
	
	// Создание файла в ИБ.
	Попытка
		
		Если РаботаСФайламиСлужебныйКлиентПовтИсп.ЭтоСправочникФайлы(ПараметрыВыполнения.ВладелецФайла) Тогда
			
			СведенияОФайле = РаботаСФайламиКлиентСервер.СведенияОФайле("ФайлСВерсией");
			СведенияОФайле.АдресВременногоХранилищаФайла = Адрес;
			СведенияОФайле.ИмяБезРасширения = СтруктураПути.ИмяБезРасширения;
			СведенияОФайле.РасширениеБезТочки = ОбщегоНазначенияКлиентСервер.РасширениеБезТочки(СтруктураПути.Расширение);
			Результат.ФайлСсылка = РаботаСФайламиСлужебныйВызовСервера.СоздатьФайлСВерсией(ПараметрыВыполнения.ВладелецФайла, СведенияОФайле);
			Результат.ФайлДобавлен = Истина;
			
		Иначе
			
			ПараметрыФайла = РаботаСФайламиСлужебныйКлиентСервер.ПараметрыДобавленияФайла();
			ПараметрыФайла.ВладелецФайлов = ПараметрыВыполнения.ВладелецФайла;
			ПараметрыФайла.ИмяБезРасширения = СтруктураПути.ИмяБезРасширения;
			ПараметрыФайла.РасширениеБезТочки = ОбщегоНазначенияКлиентСервер.РасширениеБезТочки(СтруктураПути.Расширение);
			
			Результат.ФайлСсылка = РаботаСФайламиСлужебныйВызовСервера.ДобавитьФайл(ПараметрыФайла,Адрес);
			Результат.ФайлДобавлен = Истина;
			
		КонецЕсли;
		
	Исключение
		Результат.ТекстОшибки = ОшибкаСозданияНовогоФайла(ИнформацияОбОшибке());
	КонецПопытки;
	Если Результат.ТекстОшибки <> "" Тогда
		ВернутьРезультатПослеПоказаПредупреждения(ПараметрыВыполнения.ОбработчикРезультата, Результат.ТекстОшибки, Неопределено);
		Возврат;
	КонецЕсли;
	
	ПараметрыОповещения = ПараметрыОповещенияЗаписиФайла();
	ПараметрыОповещения.Владелец = ПараметрыВыполнения.ВладелецФайла;
	ПараметрыОповещения.Файл = Результат.ФайлСсылка;
	ПараметрыОповещения.ЭтоНовый = Истина;
	Оповестить("Запись_Файл", ПараметрыОповещения, Результат.ФайлСсылка);
	
	ПоказатьОповещениеПользователя(
		НСтр("ru = 'Создание:'"),
		ПолучитьНавигационнуюСсылку(Результат.ФайлСсылка),
		Результат.ФайлСсылка,
		БиблиотекаКартинок.Информация32);
	
	Если ПараметрыВыполнения.НеОткрыватьКарточкуПослеСозданияИзФайла <> Истина Тогда
		ПараметрыФормы = Новый Структура("КарточкаОткрытаПослеСозданияФайла", Истина);
		ОписаниеОповещенияОЗакрытии = ОбработчикЗавершения(ПараметрыВыполнения.ОбработчикРезультата);
		РаботаСФайламиКлиент.ОткрытьФормуФайла(Результат.ФайлСсылка,, ПараметрыФормы, ОписаниеОповещенияОЗакрытии);
	Иначе
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Результат);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ДобавитьИзФайловойСистемыБезРасширенияПослеОтветаНаВопросПовторить(Ответ, ПараметрыВыполнения) Экспорт
	
	Если Ответ = КодВозвратаДиалога.Повторить Тогда
		ДобавитьИзФайловойСистемыБезРасширения(ПараметрыВыполнения);
	Иначе
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
	КонецЕсли;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Процедуры и функции для работы с криптографией из формы файла.

// Параметры:
//  Форма - ФормаКлиентскогоПриложения
//
Процедура ПрочитатьСертификатыПодписей(Форма) Экспорт
	
	Если Форма.ЭлектронныеПодписи.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		Возврат;
	КонецЕсли;
	
	Контекст = Новый Структура;
	Контекст.Вставить("Форма", Форма);
	Контекст.Вставить("МодульЭлектроннаяПодписьКлиент",
		ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент"));
	Контекст.Вставить("МодульЭлектроннаяПодписьСлужебныйКлиентСервер",
		ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьСлужебныйКлиентСервер"));
	
	Если Контекст.МодульЭлектроннаяПодписьКлиент.ПроверятьЭлектронныеПодписиНаСервере() Тогда
		Возврат;
	КонецЕсли;
	
	НачатьПодключениеРасширенияРаботыСКриптографией(Новый ОписаниеОповещения(
		"ПрочитатьСертификатыПодписейПослеПодключенияРасширения", ЭтотОбъект, Контекст));
	
КонецПроцедуры

// Продолжение процедуры ПрочитатьСертификатыПодписей.
Процедура ПрочитатьСертификатыПодписейПослеПодключенияРасширения(Подключено, Контекст) Экспорт
	
	Если Не Подключено Тогда
		Возврат;
	КонецЕсли;
	
	Контекст.МодульЭлектроннаяПодписьКлиент.СоздатьМенеджерКриптографии(Новый ОписаниеОповещения(
			"ПрочитатьСертификатыПодписейПослеСозданияМенеджераКриптографии", ЭтотОбъект, Контекст),
		"ПолучениеСертификатов", Ложь);
	
КонецПроцедуры

// Продолжение процедуры ПрочитатьСертификатыПодписей.
Процедура ПрочитатьСертификатыПодписейПослеСозданияМенеджераКриптографии(Результат, Контекст) Экспорт
	
	Если ТипЗнч(Результат) <> Тип("МенеджерКриптографии") Тогда
		Возврат;
	КонецЕсли;
	
	Контекст.Вставить("Индекс", -1);
	Контекст.Вставить("МенеджерКриптографии", Результат);
	ПрочитатьСертификатыПодписейЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ПрочитатьСертификатыПодписей.
//
// Параметры:
//   Контекст - Структура:
//    * Форма - ФормаКлиентскогоПриложения
//
Процедура ПрочитатьСертификатыПодписейЦиклНачало(Контекст)
	
	Если Контекст.Форма.ЭлектронныеПодписи.Количество() <= Контекст.Индекс + 1 Тогда
		Возврат;
	КонецЕсли;
	Контекст.Индекс = Контекст.Индекс + 1;
	Контекст.Вставить("СтрокаТаблицы", Контекст.Форма.ЭлектронныеПодписи[Контекст.Индекс]);
	
	Если ЗначениеЗаполнено(Контекст.СтрокаТаблицы.Отпечаток) Тогда
		ПрочитатьСертификатыПодписейЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	// Подпись не была прочитана при записи объекта.
	Подпись = ПолучитьИзВременногоХранилища(Контекст.СтрокаТаблицы.АдресПодписи);
	
	Если Не ЗначениеЗаполнено(Подпись) Тогда
		ПрочитатьСертификатыПодписейЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	Контекст.МенеджерКриптографии.НачатьПолучениеСертификатовИзПодписи(Новый ОписаниеОповещения(
			"ПрочитатьСертификатыПодписейЦиклПослеПолученияСертификатовИзПодписи", ЭтотОбъект, Контекст,
			"ПрочитатьСертификатыПодписейЦиклПослеОшибкиПолученияСертификатовИзПодписи", ЭтотОбъект),
		Подпись);
	
КонецПроцедуры

// Продолжение процедуры ПрочитатьСертификатыПодписей.
Процедура ПрочитатьСертификатыПодписейЦиклПослеОшибкиПолученияСертификатовИзПодписи(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	ПрочитатьСертификатыПодписейЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ПрочитатьСертификатыПодписей.
Процедура ПрочитатьСертификатыПодписейЦиклПослеПолученияСертификатовИзПодписи(Сертификаты, Контекст) Экспорт
	
	Если Сертификаты.Количество() = 0 Тогда
		ПрочитатьСертификатыПодписейЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	Попытка
		Если Сертификаты.Количество() = 1 Тогда
			Сертификат = Сертификаты[0]; // СертификатКриптографии
		ИначеЕсли Сертификаты.Количество() > 1 Тогда
			Сертификат = Контекст.МодульЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатыПоПорядкуДоКорневого(Сертификаты)[0]; // СертификатКриптографии
		КонецЕсли;
	Исключение
		ПрочитатьСертификатыПодписейЦиклНачало(Контекст);
		Возврат;
	КонецПопытки;

	Контекст.Вставить("Сертификат", Сертификат);
	Сертификат.НачатьВыгрузку(Новый ОписаниеОповещения(
		"ПрочитатьСертификатыПодписейЦиклПослеВыгрузкиСертификата", ЭтотОбъект, Контекст,
		"ПрочитатьСертификатыПодписейЦиклПослеОшибкиВыгрузкиСертификата", ЭтотОбъект));
	
КонецПроцедуры

// Продолжение процедуры ПрочитатьСертификатыПодписей.
Процедура ПрочитатьСертификатыПодписейЦиклПослеОшибкиВыгрузкиСертификата(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	ПрочитатьСертификатыПодписейЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ПрочитатьСертификатыПодписей.
//
// Параметры:
//   Контекст - Структура:
//    * Форма - ФормаКлиентскогоПриложения
//
Процедура ПрочитатьСертификатыПодписейЦиклПослеВыгрузкиСертификата(ДанныеСертификата, Контекст) Экспорт
	
	СтрокаТаблицы = Контекст.СтрокаТаблицы;
	
	СтрокаТаблицы.Отпечаток = Base64Строка(Контекст.Сертификат.Отпечаток);
	СтрокаТаблицы.АдресСертификата = ПоместитьВоВременноеХранилище(ДанныеСертификата, Контекст.Форма.УникальныйИдентификатор);
	СтрокаТаблицы.КомуВыданСертификат = Контекст.МодульЭлектроннаяПодписьКлиент.ПредставлениеСубъекта(Контекст.Сертификат);
	
	ПрочитатьСертификатыПодписейЦиклНачало(Контекст);
	
КонецПроцедуры


// По окончании Зашифровать нотифицирует.
// Параметры:
//  МассивФайловВРабочемКаталогеДляУдаления - Массив - массив строк - путей к файлам.
//  ВладелецФайла  - ЛюбаяСсылка - владелец файла.
//  ФайлСсылка  - СправочникСсылка.Файлы - файл.
//
Процедура ИнформироватьОШифровании(МассивФайловВРабочемКаталогеДляУдаления,
                                   ВладелецФайла,
                                   ФайлСсылка) Экспорт
	
	ОповеститьОбИзменении(ФайлСсылка);
	Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ПрисоединенныйФайлЗашифрован"), ВладелецФайла);
	Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ДанныеФайлаИзменены"), ФайлСсылка);
	
	// Удаляем из рабочего каталога все версии файла.
	Для Каждого ПолноеИмяФайла Из МассивФайловВРабочемКаталогеДляУдаления Цикл
		УдалитьФайлБезПодтверждения(ПолноеИмяФайла);
	КонецЦикла;
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		Возврат;
	КонецЕсли;
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	МодульЭлектроннаяПодписьКлиент.ИнформироватьОШифрованииОбъекта(
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Файл: %1'"), ФайлСсылка));
	
КонецПроцедуры

// По окончании Расшифровать нотифицирует.
// Параметры:
//  ВладелецФайла  - ЛюбаяСсылка - владелец файла.
//  ФайлСсылка  - СправочникСсылка.Файлы - файл.
//
Процедура ИнформироватьОРасшифровке(ВладелецФайла, ФайлСсылка) Экспорт
	
	ОповеститьОбИзменении(ФайлСсылка);
	Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ПрисоединенныйФайлЗашифрован"), ВладелецФайла);
	Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ДанныеФайлаИзменены"), ФайлСсылка);
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		Возврат;
	КонецЕсли;
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	МодульЭлектроннаяПодписьКлиент.ИнформироватьОРасшифровкеОбъекта(
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Файл: %1'"), ФайлСсылка));
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Работа с электронными подписями.
//
Процедура ПодписатьФайл(ПрисоединенныйФайл, ДанныеФайла, ИдентификаторФормы,
			ОбработчикЗавершения = Неопределено, ОбработчикПриПолученииПодписи = Неопределено, ПараметрыПодписи = Неопределено) Экспорт
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикЗавершения", ОбработчикЗавершения);
	ПараметрыВыполнения.Вставить("ПрисоединенныйФайл",   ПрисоединенныйФайл);
	ПараметрыВыполнения.Вставить("ДанныеФайла",          ДанныеФайла);
	ПараметрыВыполнения.Вставить("ИдентификаторФормы",   ИдентификаторФормы);
	
	ОбработчикПродолжения = Новый ОписаниеОповещения("ПослеДобавленияПодписей", ЭтотОбъект, ПараметрыВыполнения);
	Если Не ПроверитьВозможностьПодписания(ДанныеФайла, ОбработчикЗавершения, ОбработчикПродолжения, ПараметрыВыполнения) Тогда
		Возврат;
	КонецЕсли;
	
	ОписаниеДанных = Новый Структура;
	ОписаниеДанных.Вставить("ПоказатьКомментарий", Истина);
	
	ПодписьМассиваФайлов = ТипЗнч(ПрисоединенныйФайл) = Тип("Массив");
	
	Если ПодписьМассиваФайлов И ПрисоединенныйФайл.Количество() > 1 Тогда
		
		ОписаниеДанных.Вставить("Операция",            НСтр("ru = 'Подписание файлов'"));
		ОписаниеДанных.Вставить("ЗаголовокДанных",     НСтр("ru = 'Файлы'"));
		
		НаборДанных = Новый Массив;
		ИндексФайла = 0;
		Для Каждого Файл Из ПрисоединенныйФайл Цикл
			
			ОписаниеДанныхФайла = Новый Структура;
			ОписаниеДанныхФайла.Вставить("Представление", Файл);
			ОписаниеДанныхФайла.Вставить("Данные", ПараметрыВыполнения.ДанныеФайла[ИндексФайла].СсылкаНаДвоичныеДанныеФайла);
			
			Если ОбработчикПриПолученииПодписи = Неопределено Тогда
				ОписаниеДанныхФайла.Вставить("Объект", Файл);
			Иначе
				ОписаниеДанныхФайла.Вставить("Объект", ОбработчикПриПолученииПодписи);
			КонецЕсли;
			
			НаборДанных.Добавить(ОписаниеДанныхФайла);
			ИндексФайла = ИндексФайла + 1;
			
		КонецЦикла;
		
		ОписаниеДанных.Вставить("НаборДанных", НаборДанных);
		ОписаниеДанных.Вставить("ПредставлениеНабора", "Файлы (%1)");
		
	Иначе
		
		ОписаниеДанных.Вставить("Операция",        НСтр("ru = 'Подписание файла'"));
		ОписаниеДанных.Вставить("ЗаголовокДанных", НСтр("ru = 'Файл'"));
		
		Если ПодписьМассиваФайлов Тогда
			ОписаниеДанных.Вставить("Представление", ПрисоединенныйФайл[0]);
			ОписаниеДанных.Вставить("Данные", ПараметрыВыполнения.ДанныеФайла[0].СсылкаНаДвоичныеДанныеФайла);
			Если ОбработчикПриПолученииПодписи = Неопределено Тогда
				ОписаниеДанных.Вставить("Объект", ПрисоединенныйФайл[0]);
			Иначе
				ОписаниеДанных.Вставить("Объект", ОбработчикПриПолученииПодписи);
			КонецЕсли;
		Иначе
			ОписаниеДанных.Вставить("Представление", ПрисоединенныйФайл);
			ОписаниеДанных.Вставить("Данные", ПараметрыВыполнения.ДанныеФайла.СсылкаНаДвоичныеДанныеФайла);
			Если ОбработчикПриПолученииПодписи = Неопределено Тогда
				ОписаниеДанных.Вставить("Объект", ПрисоединенныйФайл);
			Иначе
				ОписаниеДанных.Вставить("Объект", ОбработчикПриПолученииПодписи);
			КонецЕсли;
		КонецЕсли;
		
	КонецЕсли;
	
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	ПараметрыПодписания = МодульЭлектроннаяПодписьКлиент.НовыйТипПодписи();
	Если ПараметрыПодписи <> Неопределено Тогда
		ЗаполнитьЗначенияСвойств(ПараметрыПодписания, ПараметрыПодписи);
	КонецЕсли;
	МодульЭлектроннаяПодписьКлиент.Подписать(ОписаниеДанных, ИдентификаторФормы, ОбработчикПродолжения, ПараметрыПодписания);
	
КонецПроцедуры

// Завершение процедур ПодписатьФайл, ДобавитьПодписьИзФайла.
Процедура ПослеДобавленияПодписей(ОписаниеДанных, ПараметрыВыполнения) Экспорт
	
	Если ТипЗнч(ОписаниеДанных) <> Тип("Структура")
		Или Не ОписаниеДанных.Свойство("Успех") Тогда
		
		ВыполнитьОбработкуОповещения(ПараметрыВыполнения.ОбработчикЗавершения, Ложь);
		Возврат;
	КонецЕсли;
	
	Если ОписаниеДанных.Успех Тогда
		Если ТипЗнч(ПараметрыВыполнения.ПрисоединенныйФайл) = Тип("Массив") Тогда
			
			Для Каждого Файл Из ПараметрыВыполнения.ПрисоединенныйФайл Цикл
				ОповеститьОбИзменении(Файл);
				Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла(), Файл);
			КонецЦикла;
			
		Иначе
			ОповеститьОбИзменении(ПараметрыВыполнения.ПрисоединенныйФайл);
			Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла(), ПараметрыВыполнения.ПрисоединенныйФайл);
		КонецЕсли;
	КонецЕсли;
	
	Если ПараметрыВыполнения.ОбработчикЗавершения <> Неопределено Тогда
		ВыполнитьОбработкуОповещения(ПараметрыВыполнения.ОбработчикЗавершения, ОписаниеДанных.Успех);
	КонецЕсли;
	
КонецПроцедуры

// Добавляет электронные подписи к файлу в программе из файлов-подписей на компьютере.
Процедура ДобавитьПодписьИзФайла(Файл, ИдентификаторФормы, ОбработчикЗавершения) Экспорт
	
	СвойстваФайла = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИДвоичныеДанные(Файл, , ИдентификаторФормы);
	ДанныеФайла = СвойстваФайла.ДанныеФайла;
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикЗавершения", ОбработчикЗавершения);
	ПараметрыВыполнения.Вставить("ДанныеФайла", ДанныеФайла);
	ПараметрыВыполнения.Вставить("ИдентификаторФормы", ИдентификаторФормы);
	
	Если Не ПроверитьВозможностьПодписания(ПараметрыВыполнения.ДанныеФайла,
		ОбработчикЗавершения, ОбработчикЗавершения, ПараметрыВыполнения) Тогда
		
		Возврат;
		
	КонецЕсли;
	
	ОписаниеДанных = Новый Структура;
	ОписаниеДанных.Вставить("ЗаголовокДанных",     НСтр("ru = 'Файл'"));
	ОписаниеДанных.Вставить("Представление",       ДанныеФайла.Ссылка);
	ОписаниеДанных.Вставить("ПоказатьКомментарий", Истина);
	ОписаниеДанных.Вставить("Данные",              СвойстваФайла.ДвоичныеДанные);
	
	ОписаниеДанных.Вставить("Объект",
		Новый ОписаниеОповещения("ПриПолученииПодписей", ЭтотОбъект, ПараметрыВыполнения));
	
	ОбработчикПродолжения = Новый ОписаниеОповещения("ПослеПодписанияФайла",
		ЭтотОбъект, ПараметрыВыполнения);
	
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	МодульЭлектроннаяПодписьКлиент.ДобавитьПодписьИзФайла(ОписаниеДанных,, ОбработчикПродолжения);
	
КонецПроцедуры

// Продолжение процедуры ДобавитьПодписьИзФайла.
// Вызывается из подсистемы ЭлектроннаяПодпись после подготовки подписей из файлов для нестандартного
// способа добавления подписи в объект.
//
// Параметры:
//   Контекст - Структура:
//     * ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//
Процедура ПриПолученииПодписей(Параметры, Контекст) Экспорт
	
	РаботаСФайламиСлужебныйВызовСервера.ДобавитьПодписьКФайлу(
		Контекст.ДанныеФайла.Ссылка,
		Параметры.ОписаниеДанных.Подписи,
		Контекст.ИдентификаторФормы);
	
	ВыполнитьОбработкуОповещения(Параметры.Оповещение, Новый Структура);
	
КонецПроцедуры

// Завершение процедуры ДобавитьПодписьИзФайла.
Процедура ПослеПодписанияФайла(ОписаниеДанных, ПараметрыВыполнения) Экспорт
	
	Если ТипЗнч(ОписаниеДанных) <> Тип("Структура")
		Или Не ОписаниеДанных.Свойство("Успех") Тогда
		
		ВыполнитьОбработкуОповещения(ПараметрыВыполнения.ОбработчикЗавершения, Ложь);
		Возврат;
	КонецЕсли;
	
	Если ОписаниеДанных.Успех Тогда
		ОповеститьОбИзмененииФайла(ПараметрыВыполнения.ДанныеФайла);
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикЗавершения, ОписаниеДанных.Успех);
	
КонецПроцедуры

// Для процедур ПослеПодписанияФайла, ПослеПодписанияФайлов.
Процедура ОповеститьОбИзмененииФайла(ДанныеФайла)
	
	ОповеститьОбИзменении(ДанныеФайла.Ссылка);
	ОповеститьОбИзменении(ДанныеФайла.ТекущаяВерсия);
	
	Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла("ПрисоединенныйФайлПодписан"), ДанныеФайла.Владелец);
	
КонецПроцедуры

// Сохраняет файл с электронной подписью.
Процедура СохранитьФайлВместеСПодписью(Файл, ИдентификаторФормы) Экспорт
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		Возврат;
	КонецЕсли;
	
	ДанныеФайла = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаДляСохранения(Файл);
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ДанныеФайла", ДанныеФайла);
	ПараметрыВыполнения.Вставить("ИдентификаторФормы", ИдентификаторФормы);
	
	ОписаниеДанных = Новый Структура;
	ОписаниеДанных.Вставить("ЗаголовокДанных",     НСтр("ru = 'Файл'"));
	ОписаниеДанных.Вставить("Представление",       ПараметрыВыполнения.ДанныеФайла.Ссылка);
	ОписаниеДанных.Вставить("ПоказатьКомментарий", Истина);
	ОписаниеДанных.Вставить("Объект",              ПараметрыВыполнения.ДанныеФайла.Ссылка);
	
	ОписаниеДанных.Вставить("Данные",
		Новый ОписаниеОповещения("ПриСохраненииДанныхФайла", ЭтотОбъект, ПараметрыВыполнения));
	
	МодульЭлектроннаяПодписьКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("ЭлектроннаяПодписьКлиент");
	МодульЭлектроннаяПодписьКлиент.СохранитьДанныеВместеСПодписью(ОписаниеДанных);
	
КонецПроцедуры

// Продолжение процедуры СохранитьФайлВместеСПодписями.
// Вызывается из подсистемы ЭлектроннаяПодпись после выбора подписей для сохранения.
//
Процедура ПриСохраненииДанныхФайла(Параметры, Контекст) Экспорт
	
	ДополнительныеПараметры = Новый Структура("Оповещение", Параметры.Оповещение);
	ОбработчикОповещения = Новый ОписаниеОповещения("ПриСохраненииДанныхФайлаВернутьРезультат", ЭтотОбъект, ДополнительныеПараметры);
	СохранитьКак(ОбработчикОповещения, Контекст.ДанныеФайла, Контекст.ИдентификаторФормы);
	
КонецПроцедуры

// Продолжение процедуры СохранитьФайлВместеСПодписями.
// Вызывается из подсистемы ЭлектроннаяПодпись после выбора подписей для сохранения.
//
Процедура ПриСохраненииДанныхФайлаВернутьРезультат(Результат, ДополнительныеПараметры) Экспорт

	Если ТипЗнч(Результат) = Тип("Строка") Тогда
		Результат = ?(ЗначениеЗаполнено(Результат), Новый Структура("ПолноеИмяФайла", Результат), Новый Структура);
	КонецЕсли;
	ВыполнитьОбработкуОповещения(ДополнительныеПараметры.Оповещение, Результат);

КонецПроцедуры

Функция ПроверитьВозможностьПодписания(ДанныеФайла, ОбработчикЗавершения, ОбработчикРезультата, ПараметрыВыполнения)
	
	Если Не ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись") Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Если ТипЗнч(ДанныеФайла) = Тип("Массив") Тогда
		
		Предупреждения = Новый Массив;
		Для Каждого Файл Из ДанныеФайла Цикл
			Если ЗначениеЗаполнено(Файл.Редактирует) Тогда
				Предупреждения.Добавить(РаботаСФайламиСлужебныйКлиентСервер.СтрокаСообщенияОНедопустимостиПодписанияЗанятогоФайла(Файл.Ссылка));
				Продолжить;
			КонецЕсли;
			
			Если Файл.Зашифрован Тогда
				Предупреждения.Добавить(РаботаСФайламиСлужебныйКлиентСервер.СтрокаСообщенияОНедопустимостиПодписанияЗашифрованногоФайла(Файл.Ссылка));
				Продолжить;
			КонецЕсли;
		КонецЦикла;
		
		Если Предупреждения.Количество() > 0 Тогда
			ВернутьРезультатПослеПоказаПредупреждения(ОбработчикРезультата, СтрСоединить(Предупреждения, Символы.ПС), ПараметрыВыполнения);
			Возврат Ложь;
		КонецЕсли;
		
	Иначе
	
		Если ЗначениеЗаполнено(ДанныеФайла.Редактирует) Тогда
			ТекстПредупреждения = РаботаСФайламиСлужебныйКлиентСервер.СтрокаСообщенияОНедопустимостиПодписанияЗанятогоФайла();
			ВернутьРезультатПослеПоказаПредупреждения(ОбработчикРезультата, ТекстПредупреждения, ПараметрыВыполнения);
			Возврат Ложь;
		КонецЕсли;
		
		Если ДанныеФайла.Зашифрован Тогда
			ТекстПредупреждения = РаботаСФайламиСлужебныйКлиентСервер.СтрокаСообщенияОНедопустимостиПодписанияЗашифрованногоФайла();
			ВернутьРезультатПослеПоказаПредупреждения(ОбработчикЗавершения, ТекстПредупреждения, ПараметрыВыполнения);
			Возврат Ложь;
		КонецЕсли;
	
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Загружает структуру файлов и каталогов с компьютера в программу.

// Возвращаемое значение:
//  Структура:
//    * ОбработчикРезультата      - ОписаниеОповещения - обработчик, которому нужно передать результат импорта.
//    * Владелец                  - ОпределяемыйТип.ВладелецПрисоединенныхФайлов - папка или объект-владелец, к которому
//                                                                                 добавляются импортированные файлы.
//    * ГруппаФайлов              - ОпределяемыйТип.ПрисоединенныйФайл - группа файлов, в которую добавляются
//                                                                       импортированные файлы.
//    * ВыбранныеФайлы            - СписокЗначений - импортируемые объекты Файл.
//    * Индикатор                 - Число - число от 0 до 100 - прогресс выполнения.
//    * Комментарий               - Строка - комментарий.
//    * ХранитьВерсии             - Булево - хранить версии.
//    * УдалятьФайлыПослеДобавления - Булево - удалять файлы ВыбранныеФайлы после завершения импорта.
//    * Рекурсивно                - Булево - рекурсивно обходить подкаталоги.
//    * ИдентификаторФормы        - УникальныйИдентификатор - идентификатор формы.
//    * ПсевдоФайловаяСистема     - Соответствие - эмуляция файловой системы - для строки (каталога) возвращает массив
//                                                 строк (подкаталоги и файлы).
//    * Кодировка                 - Строка - кодировка для текстовых файлов.
//    * ДобавленныеФайлы          - Массив - добавленные файлы, выходной параметр.
//
Функция ПараметрыИмпортаФайлов() Экспорт
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("ОбработчикРезультата");
	ПараметрыВыполнения.Вставить("Владелец");
	ПараметрыВыполнения.Вставить("ГруппаФайлов");
	ПараметрыВыполнения.Вставить("ВыбранныеФайлы");
	ПараметрыВыполнения.Вставить("Комментарий");
	ПараметрыВыполнения.Вставить("ХранитьВерсии");
	ПараметрыВыполнения.Вставить("УдалятьФайлыПослеДобавления");
	ПараметрыВыполнения.Вставить("Рекурсивно");
	ПараметрыВыполнения.Вставить("ИдентификаторФормы");
	ПараметрыВыполнения.Вставить("ПсевдоФайловаяСистема", Новый Соответствие);
	ПараметрыВыполнения.Вставить("Кодировка");
	ПараметрыВыполнения.Вставить("ДобавленныеФайлы", Новый Массив);
	Возврат ПараметрыВыполнения;
КонецФункции

// Рекурсивная функция импорта файлов - принимает массив файлов (или каталогов)
// - если файл, просто добавляет его, если каталог - создает группу и рекурсивно вызывает саму себя.
//
// Параметры:
//  ПараметрыВыполнения   - Структура:
//    * ОбработчикРезультата      - ОписаниеОповещения
//                                - Структура - обработчик, которому нужно передать результат
//                                  импорта.
//    * Владелец                  - ЛюбаяСсылка - владелец файла.
//    * ВыбранныеФайлы            - Массив
//                                - СписокЗначений - объекты Файл.
//    * Индикатор                 - Число - число от 0 до 100 - прогресс выполнения.
//    * МассивИменФайловСОшибками - Массив - массив имен файлов с ошибками.
//    * МассивСтруктурВсехФайлов  - Массив - массив структур всех файлов.
//    * Комментарий               - Строка - комментарий.
//    * ХранитьВерсии             - Булево - хранить версии.
//    * УдалятьФайлыПослеДобавления - Булево - удалять файлы ВыбранныеФайлы после завершения импорта.
//    * Рекурсивно                - Булево - рекурсивно обходить подкаталоги.
//    * КоличествоСуммарное       - Число - количество суммарное импортированных файлов.
//    * Счетчик                   - Число - счетчик обработанных файлов (не обязательно файл будет загружен).
//    * ИдентификаторФормы        - УникальныйИдентификатор - идентификатор формы.
//    * ПсевдоФайловаяСистема     - Соответствие - эмуляция файловой системы - для строки (каталога) возвращает массив
//                                                 строк (подкаталоги и файлы).
//    * ДобавленныеФайлы          - Массив - добавленные файлы, выходной параметр.
//    * МассивВсехПапок           - Массив - массив всех папок.
//    * Кодировка                 - Строка - кодировка для текстовых файлов.
//
Процедура ИмпортФайловРекурсивно(Владелец, ВыбранныеФайлы, ПараметрыВыполнения)
	
	СлужебныеПараметры = Новый Структура;
	Для Каждого КлючИЗначение Из ПараметрыВыполнения Цикл
		СлужебныеПараметры.Вставить(КлючИЗначение.Ключ, КлючИЗначение.Значение);
	КонецЦикла;
	СлужебныеПараметры.ОбработчикРезультата = ПараметрыВыполнения;
	СлужебныеПараметры.Владелец = Владелец;
	СлужебныеПараметры.ВыбранныеФайлы = ВыбранныеФайлы;
	
	СлужебныеПараметры.Вставить("МассивПапокДляВопросаПапкаУжеСуществует", Новый Массив);
	ИмпортФайловРекурсивноБезДиалогов(СлужебныеПараметры.Владелец, СлужебныеПараметры.ВыбранныеФайлы, СлужебныеПараметры, Истина); 
	Если СлужебныеПараметры.МассивПапокДляВопросаПапкаУжеСуществует.Количество() = 0 Тогда
		// Задавать вопрос не требуется.
		ВернутьРезультат(СлужебныеПараметры.ОбработчикРезультата, Неопределено);
		Возврат;
	КонецЕсли;
	
	// По мере ответов на вопросы папки из ПараметрыВыполнения.МассивПапокДляВопросаПапкаУжеСуществует 
	// записываются в ПараметрыВыполнения.ВыбранныеФайлы.
	// Затем рекурсия перезапускается.
	СлужебныеПараметры.ВыбранныеФайлы = Новый Массив;
	СлужебныеПараметры.Вставить("ПапкаДляДобавленияВВыбранныеФайлы", Неопределено);
	ИмпортФайловРекурсивноЗадатьСледующийВопрос(СлужебныеПараметры);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//  ПараметрыВыполнения - Структура:
//   * ВыбранныеФайлы - Массив
//   * ПапкаДляДобавленияВВыбранныеФайлы - Файл
//   * МассивПапокДляВопросаПапкаУжеСуществует - Массив
//
Процедура ИмпортФайловРекурсивноЗадатьСледующийВопрос(ПараметрыВыполнения)
	
	ПараметрыВыполнения.ОбработчикРезультата = ОбработчикЗавершения(ПараметрыВыполнения.ОбработчикРезультата);
	ПараметрыВыполнения.ПапкаДляДобавленияВВыбранныеФайлы = ПараметрыВыполнения.МассивПапокДляВопросаПапкаУжеСуществует[0];
	ПараметрыВыполнения.МассивПапокДляВопросаПапкаУжеСуществует.Удалить(0);
	
	ТекстВопроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Папка ""%1"" уже существует.
		           |Продолжить импорт папки?'"),
		ПараметрыВыполнения.ПапкаДляДобавленияВВыбранныеФайлы.Имя);
	
	Обработчик = Новый ОписаниеОповещения("ИмпортФайловРекурсивноПослеОтветаНаВопрос", ЭтотОбъект, ПараметрыВыполнения);
	
	ПоказатьВопрос(Обработчик, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
//
// Параметры:
//   ПараметрыВыполнения - Структура:
//     * ВыбранныеФайлы - Массив
//
Процедура ИмпортФайловРекурсивноПослеОтветаНаВопрос(Ответ, ПараметрыВыполнения) Экспорт
	
	Если Ответ <> КодВозвратаДиалога.Нет Тогда
		ПараметрыВыполнения.ВыбранныеФайлы.Добавить(ПараметрыВыполнения.ПапкаДляДобавленияВВыбранныеФайлы);
	КонецЕсли;
	
	// После ответов на все вопросы рекурсия перезапускается.
	Если ПараметрыВыполнения.МассивПапокДляВопросаПапкаУжеСуществует.Количество() = 0 Тогда
		ИмпортФайловРекурсивноБезДиалогов(ПараметрыВыполнения.Владелец,	ПараметрыВыполнения.ВыбранныеФайлы, ПараметрыВыполнения,
			Ложь); // ЗадаватьВопросПапкаУжеСуществует (используется только для первого уровня рекурсии).
		
		Если ПараметрыВыполнения.МассивПапокДляВопросаПапкаУжеСуществует.Количество() = 0 Тогда
			// Вопросов больше не возникло.
			ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, Неопределено);
			Возврат;
		Иначе
			// Возникли еще вопросы.
			ПараметрыВыполнения.ВыбранныеФайлы = Новый Массив;
		КонецЕсли;
	КонецЕсли;
	
	ИмпортФайловРекурсивноЗадатьСледующийВопрос(ПараметрыВыполнения);
	
КонецПроцедуры

// Рекурсивная функция импорта файлов - принимает массив файлов (или каталогов)
// - если файл, просто добавляет его, если каталог - создает группу и рекурсивно вызывает саму себя.
//
// Параметры:
//  Владелец            - ЛюбаяСсылка - владелец файла.
//  ВыбранныеФайлы      - Массив - массив объектов Файл.
//  ПараметрыВыполнения - см. ИмпортФайловРекурсивно.ПараметрыВыполнения
//  ЗадаватьВопросПапкаУжеСуществует - Булево - Истина только для первого уровня рекурсии.
//
Процедура ИмпортФайловРекурсивноБезДиалогов(Знач Владелец, Знач ВыбранныеФайлы, Знач ПараметрыВыполнения, Знач ЗадаватьВопросПапкаУжеСуществует)
	
	Перем ПерваяПапкаСТакимЖеИменем;
	
	Для Каждого ВыбранныйФайл Из ВыбранныеФайлы Цикл
		
		Если Не ВыбранныйФайл.Существует() Тогда
			Запись = Новый Структура;
			Запись.Вставить("ИмяФайла", ВыбранныйФайл.ПолноеИмя);
			Запись.Вставить("Ошибка", НСтр("ru = 'Файл отсутствует на компьютере.'"));
			ПараметрыВыполнения.МассивИменФайловСОшибками.Добавить(Запись);
			Продолжить;
		КонецЕсли;
		
		Попытка
			
			Если ВыбранныйФайл.Расширение = ".lnk" Тогда
				ВыбранныйФайл = РазыменоватьLnkФайл(ВыбранныйФайл);
			КонецЕсли;
			
			Если ВыбранныйФайл.ЭтоКаталог() Тогда
				
				Если ПараметрыВыполнения.Рекурсивно = Истина Тогда
					НовыйПуть = Строка(ВыбранныйФайл.Путь);
					НовыйПуть = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(НовыйПуть);
					НовыйПуть = НовыйПуть + Строка(ВыбранныйФайл.Имя);
					МассивФайлов = НайтиФайлыПсевдо(ПараметрыВыполнения.ПсевдоФайловаяСистема, НовыйПуть);
					
					// Создаем группу в справочнике - эквивалент каталога на компьютере.
					Если МассивФайлов.Количество() <> 0 Тогда
						ИмяФайла = ВыбранныйФайл.Имя;
						
						Если РаботаСФайламиСлужебныйВызовСервера.ЕстьПапкаСТакимИменем(ИмяФайла, ПараметрыВыполнения.ГруппаФайлов, ПерваяПапкаСТакимЖеИменем) Тогда
							
							Если ЗадаватьВопросПапкаУжеСуществует Тогда
								ПараметрыВыполнения.МассивПапокДляВопросаПапкаУжеСуществует.Добавить(ВыбранныйФайл);
								Продолжить;
							КонецЕсли;
						КонецЕсли;
						
						ПапкаФайловСсылка = РаботаСФайламиСлужебныйВызовСервера.СоздатьПапкуФайлов(ИмяФайла, Владелец,,ПараметрыВыполнения.ГруппаФайлов);
						Если РаботаСФайламиСлужебныйКлиентПовтИсп.ЭтоСправочникФайлы(ПапкаФайловСсылка) Тогда
							// Параметр ЗадаватьВопросПапкаУжеСуществует нужен, чтобы не задавать вопрос на 1 уровне рекурсии,
							// когда обходятся папки, для которых уже получен положительный ответ.
							ИмпортФайловРекурсивноБезДиалогов(ПапкаФайловСсылка, МассивФайлов, ПараметрыВыполнения, Истина);
						Иначе
							ТекущаяГруппаФайлов = ПараметрыВыполнения.ГруппаФайлов;
							ПараметрыВыполнения.ГруппаФайлов = ПапкаФайловСсылка;
							// Параметр ЗадаватьВопросПапкаУжеСуществует нужен, чтобы не задавать вопрос на 1 уровне рекурсии,
							// когда обходятся папки, для которых уже получен положительный ответ.
							ИмпортФайловРекурсивноБезДиалогов(Владелец, МассивФайлов, ПараметрыВыполнения, Истина);
							ПараметрыВыполнения.ГруппаФайлов = ТекущаяГруппаФайлов;
						КонецЕсли;
						
						ПараметрыВыполнения.МассивВсехПапок.Добавить(НовыйПуть);
					КонецЕсли;
				КонецЕсли;
				
				Продолжить;
			КонецЕсли;
			
			Если Не ПроверитьВозможностьЗагрузкиФайла(
			          ВыбранныйФайл, Ложь, ПараметрыВыполнения.МассивИменФайловСОшибками) Тогда
				Продолжить;
			КонецЕсли;
			
			// Обновим индикатор прогресса.
			ПараметрыВыполнения.Счетчик = ПараметрыВыполнения.Счетчик + 1;
			// Считаем проценты
			ПараметрыВыполнения.Индикатор = Цел(ПараметрыВыполнения.Счетчик * 100 / ПараметрыВыполнения.КоличествоСуммарное);
			РазмерВМб = ВыбранныйФайл.Размер() / (1024 * 1024);
			НадписьПодробнее = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Обрабатывается файл ""%1"" (%2 Мб)...'"),
				ВыбранныйФайл.Имя, 
				РаботаСФайламиСлужебныйКлиентСервер.ПолучитьСтрокуСРазмеромФайла(РазмерВМб));
				
			ТекстСостояния = НСтр("ru = 'Загрузка файлов с компьютера...'");
			
			Состояние(ТекстСостояния,
				ПараметрыВыполнения.Индикатор,
				НадписьПодробнее,
				БиблиотекаКартинок.Информация32);
			
			// Создаем Элемент справочника Файлы.
			АдресВременногоХранилищаФайла = "";
			
			ПомещаемыеФайлы = Новый Массив;
			Описание = Новый ОписаниеПередаваемогоФайла(ВыбранныйФайл.ПолноеИмя, "");
			ПомещаемыеФайлы.Добавить(Описание);
			
			ПомещенныеФайлы = Новый Массив;			
			Если Не ПоместитьФайлы(ПомещаемыеФайлы, ПомещенныеФайлы, , Ложь, ПараметрыВыполнения.ИдентификаторФормы) Тогда
				ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось поместить файл во временное хранилище ""%1"".'"),
					ВыбранныйФайл.ПолноеИмя);
			КонецЕсли;
			
			Если ПомещенныеФайлы.Количество() = 1 Тогда
				АдресВременногоХранилищаФайла = ПомещенныеФайлы[0].Хранение;
			КонецЕсли;
			
			Если НЕ ОбщиеНастройкиРаботыСФайлами().ИзвлекатьТекстыФайловНаСервере Тогда
				АдресВременногоХранилищаТекста = ИзвлечьТекстВоВременноеХранилище(ВыбранныйФайл.ПолноеИмя,
					ПараметрыВыполнения.ИдентификаторФормы, , ПараметрыВыполнения.Кодировка);
			Иначе
				АдресВременногоХранилищаТекста = "";
			КонецЕсли;
			
			// Создаем элемент справочника Файлы.
			ИмпортироватьФайл(ВыбранныйФайл, Владелец, ПараметрыВыполнения, АдресВременногоХранилищаФайла, АдресВременногоХранилищаТекста);
				
		Исключение
			ИнформацияОбОшибке = ИнформацияОбОшибке();
			
			СообщениеОбОшибке = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
			ОбщегоНазначенияКлиент.СообщитьПользователю(СообщениеОбОшибке);
			ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
				"Ошибка", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке),,Истина);
			
			Запись = Новый Структура;
			Запись.Вставить("ИмяФайла", ВыбранныйФайл.ПолноеИмя);
			Запись.Вставить("Ошибка", СообщениеОбОшибке);
			ПараметрыВыполнения.МассивИменФайловСОшибками.Добавить(Запись);
			
		КонецПопытки;
	КонецЦикла;
	
КонецПроцедуры

// Параметры:
//
// ПараметрыВыполнения - см. ИмпортФайловРекурсивно.ПараметрыВыполнения
//
Процедура ИмпортироватьФайл(Знач ВыбранныйФайл, Знач Владелец, Знач ПараметрыВыполнения, Знач АдресВременногоХранилищаФайла, Знач АдресВременногоХранилищаТекста) 

	Если РаботаСФайламиСлужебныйКлиентПовтИсп.ЭтоСправочникФайлы(ПараметрыВыполнения.Владелец) Тогда
		
		СведенияОФайле = РаботаСФайламиКлиентСервер.СведенияОФайле("ФайлСВерсией", ВыбранныйФайл);
		СведенияОФайле.АдресВременногоХранилищаФайла = АдресВременногоХранилищаФайла;
		СведенияОФайле.АдресВременногоХранилищаТекста = АдресВременногоХранилищаТекста;
		СведенияОФайле.Комментарий = ПараметрыВыполнения.Комментарий;
		СведенияОФайле.Кодировка = ПараметрыВыполнения.Кодировка;

		ФайлСсылка = РаботаСФайламиСлужебныйВызовСервера.СоздатьФайлСВерсией(Владелец, СведенияОФайле);
		
	Иначе
		
		ПараметрыФайла = РаботаСФайламиСлужебныйКлиентСервер.ПараметрыДобавленияФайла();
		ПараметрыФайла.ВладелецФайлов = ПараметрыВыполнения.Владелец;
		ПараметрыФайла.ИмяБезРасширения = ВыбранныйФайл.ИмяБезРасширения;
		ПараметрыФайла.РасширениеБезТочки = ОбщегоНазначенияКлиентСервер.РасширениеБезТочки(ВыбранныйФайл.Расширение);
		ПараметрыФайла.ГруппаФайлов = ПараметрыВыполнения.ГруппаФайлов;
		
		ФайлСсылка = РаботаСФайламиСлужебныйВызовСервера.ДобавитьФайл(ПараметрыФайла,
			АдресВременногоХранилищаФайла, АдресВременногоХранилищаТекста,ПараметрыВыполнения.Комментарий);
		
	КонецЕсли;
	
	Если ПараметрыВыполнения.Кодировка <> Неопределено Тогда
		РаботаСФайламиСлужебныйВызовСервера.ЗаписатьКодировкуВерсииФайла(ФайлСсылка, ПараметрыВыполнения.Кодировка); 
	КонецЕсли;
	
	УдалитьИзВременногоХранилища(АдресВременногоХранилищаФайла);
	Если Не ПустаяСтрока(АдресВременногоХранилищаТекста) Тогда
		УдалитьИзВременногоХранилища(АдресВременногоХранилищаТекста);
	КонецЕсли;
	
	ДобавленныйФайлИПуть = Новый Структура("ФайлСсылка, Путь", ФайлСсылка, ВыбранныйФайл.Путь);
	ПараметрыВыполнения.ДобавленныеФайлы.Добавить(ДобавленныйФайлИПуть);
	
	Запись = Новый Структура;
	Запись.Вставить("ИмяФайла", ВыбранныйФайл.ПолноеИмя);
	Запись.Вставить("Файл", ФайлСсылка);
	ПараметрыВыполнения.МассивСтруктурВсехФайлов.Добавить(Запись);

КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Прочие служебные процедуры и функции.

// При переименовании файла обновляет информацию в рабочем каталоге (имя файла на компьютере и в регистре).
//
// Параметры:
//  ТекущаяВерсия  - СправочникСсылка.ВерсииФайлов - версия файла.
//  НовоеИмя       - Строка - новое имя файла.
//
Процедура ОбновитьИнформациюВРабочемКаталоге(ТекущаяВерсия, НовоеИмя) Экспорт
	
	ИмяКаталога = РабочийКаталогПользователя();
	ПолноеИмяФайла = "";	
	ВРабочемКаталогеНаЧтение = Истина;
	ВРабочемКаталогеВладельца = Ложь;	
	ФайлВРабочемКаталоге = ФайлНаходитсяВЛокальномКэшеФайлов(Неопределено, ТекущаяВерсия,
		ПолноеИмяФайла, ВРабочемКаталогеНаЧтение, ВРабочемКаталогеВладельца);
	Если Не ФайлВРабочемКаталоге Тогда
		Возврат;
	КонецЕсли;
	
	Файл = Новый Файл(ПолноеИмяФайла);
	ТолькоИмя = Файл.Имя;
	РазмерФайла = Файл.Размер();
	ПутьБезИмени = Лев(ПолноеИмяФайла, СтрДлина(ПолноеИмяФайла) - СтрДлина(ТолькоИмя));
	НовоеПолноеИмя = ПутьБезИмени + НовоеИмя + Файл.Расширение;
	ПереместитьФайл(ПолноеИмяФайла, НовоеПолноеИмя);
	
	РаботаСФайламиСлужебныйВызовСервера.УдалитьИзРегистра(ТекущаяВерсия);
	РаботаСФайламиСлужебныйВызовСервера.ЗанестиИнформациюФайлаВРегистр(ТекущаяВерсия,
		НовоеПолноеИмя, ИмяКаталога, ВРабочемКаталогеНаЧтение, РазмерФайла, ВРабочемКаталогеВладельца);
	
КонецПроцедуры

// Перерегистрировать в рабочем каталоге с другим флагом НаЧтение, если там вообще есть такой файл.
// 
// Параметры:
//  ДанныеФайла  - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//  НаЧтение - Булево - файл помещен на чтение.
//  ВРабочемКаталогеВладельца - Булево - файл в рабочем каталоге владельца (а не в основном рабочем каталоге).
//
Процедура ПеререгистрироватьФайлВРабочемКаталоге(ДанныеФайла, НаЧтение, ВРабочемКаталогеВладельца)
	
	Если ДанныеФайла.Версия.Пустая() Тогда 
		Возврат;
	КонецЕсли;

	ПолноеИмяФайла = "";	
	ВРабочемКаталогеНаЧтение = Истина;
	ФайлВРабочемКаталоге = ФайлНаходитсяВЛокальномКэшеФайлов(ДанныеФайла, ДанныеФайла.ТекущаяВерсия, ПолноеИмяФайла, 
		ВРабочемКаталогеНаЧтение, ВРабочемКаталогеВладельца);
	Если Не ФайлВРабочемКаталоге Тогда
		Возврат;
	КонецЕсли;
	
	ИмяКаталога = РабочийКаталогПользователя();
	РаботаСФайламиСлужебныйВызовСервера.ЗанестиИнформациюФайлаВРегистр(ДанныеФайла.ТекущаяВерсия, ПолноеИмяФайла, 
		ИмяКаталога, НаЧтение, 0, ВРабочемКаталогеВладельца);
	Файл = Новый Файл(ПолноеИмяФайла);
	Файл.УстановитьТолькоЧтение(НаЧтение);
	
КонецПроцедуры

// Функция предназначена для открытия файла соответствующим приложением.
//
// Параметры:
//  ДанныеФайла  - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//  ИмяОткрываемогоФайла - Строка - полное имя файла.
//  ИдентификаторВладельца - УникальныйИдентификатор - идентификатор формы-владельца.
//
Процедура ОткрытьФайлПриложением(ДанныеФайла, ИмяОткрываемогоФайла, ИдентификаторВладельца = Неопределено)
	
	Если Не РасширениеРаботыСФайламиПодключено() Тогда
		Возврат;
	КонецЕсли;
		
	ПерсональныеНастройкиРаботыСФайлами = ПерсональныеНастройкиРаботыСФайлами();
	
	ТекстовыеФайлыСпособОткрытия = ПерсональныеНастройкиРаботыСФайлами.ТекстовыеФайлыСпособОткрытия;
	Если ТекстовыеФайлыСпособОткрытия = ПредопределенноеЗначение("Перечисление.СпособыОткрытияФайлаНаПросмотр.ВоВстроенномРедакторе") Тогда
		
		ТекстовыеФайлыРасширение = ПерсональныеНастройкиРаботыСФайлами.ТекстовыеФайлыРасширение;
		Если РаботаСФайламиСлужебныйКлиентСервер.РасширениеФайлаВСписке(ТекстовыеФайлыРасширение, ДанныеФайла.Расширение) Тогда
			
			ПараметрыФормы = Новый Структура;
			ПараметрыФормы.Вставить("Файл", ДанныеФайла.Ссылка);
			ПараметрыФормы.Вставить("ДанныеФайла", ДанныеФайла);
			ПараметрыФормы.Вставить("ИмяОткрываемогоФайла", ИмяОткрываемогоФайла);
			ПараметрыФормы.Вставить("ИдентификаторВладельца", ИдентификаторВладельца);
			
			ОткрытьФорму("Обработка.РаботаСФайлами.Форма.РедактированиеТекстовогоФайла", 
				ПараметрыФормы, , ДанныеФайла.Ссылка);
			Возврат;
			
		КонецЕсли;
		
	КонецЕсли;
	
#Если Не МобильныйКлиент Тогда
	Если НРег(ДанныеФайла.Расширение) = НРег("grs") Тогда
		
		Схема = Новый ГрафическаяСхема; 
		Схема.Прочитать(ИмяОткрываемогоФайла);
		
		ЗаголовокФормы = ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(
			ДанныеФайла.ПолноеНаименованиеВерсии, ДанныеФайла.Расширение);
		
		Схема.Показать(ЗаголовокФормы, ИмяОткрываемогоФайла);
		Возврат;
		
	КонецЕсли;
#КонецЕсли
	
	Если НРег(ДанныеФайла.Расширение) = НРег("mxl") Тогда
		
		ПомещаемыеФайлы = Новый Массив;
		ПомещаемыеФайлы.Добавить(Новый ОписаниеПередаваемогоФайла(ИмяОткрываемогоФайла));
		ПомещенныеФайлы = Новый Массив;
		Если Не ПоместитьФайлы(ПомещаемыеФайлы, ПомещенныеФайлы, , Ложь) Тогда
			Возврат;
		КонецЕсли;
		ТабличныйДокумент = ПомещенныеФайлы[0].Хранение;
		
		ЗаголовокФормы = ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(
			ДанныеФайла.ПолноеНаименованиеВерсии, ДанныеФайла.Расширение);
			
		ПараметрыОткрытия = Новый Структура;
		ПараметрыОткрытия.Вставить("ИмяДокумента", ЗаголовокФормы);
		ПараметрыОткрытия.Вставить("ПутьКФайлу", ИмяОткрываемогоФайла);
		ПараметрыОткрытия.Вставить("ТабличныйДокумент", ТабличныйДокумент);
		Если Не ДанныеФайла.НаЧтение Тогда
			ПараметрыОткрытия.Вставить("ПрисоединенныйФайл", ДанныеФайла.Ссылка);
		КонецЕсли;
		
		ОткрытьФорму("ОбщаяФорма.РедактированиеТабличногоДокумента", ПараметрыОткрытия);
		
		Возврат;
		
	КонецЕсли;
	
	// Открыть Файл
	ФайловаяСистемаКлиент.ОткрытьФайл(ИмяОткрываемогоФайла);
	
КонецПроцедуры

// Возвращает параметры для работы с занятыми файлами.
// Возвращает:
//	Неопределено - если нет редактируемых файлов или работать с ними не надо.
//	Структуру - структура с передаваемыми параметрами.
// 
Функция ПроверитьЗанятыеФайлыПриЗавершенииРаботы()
	
	Если ПользователиКлиент.ЭтоСеансВнешнегоПользователя() Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ПерсональныеНастройкиРаботыСФайлами = СтандартныеПодсистемыКлиент.ПараметрКлиента("ПерсональныеНастройкиРаботыСФайлами");
	ПоказыватьЗанятыеФайлыПриЗавершенииРаботы = ПерсональныеНастройкиРаботыСФайлами.ПоказыватьЗанятыеФайлыПриЗавершенииРаботы;
	
	Если Не ПоказыватьЗанятыеФайлыПриЗавершенииРаботы Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	КоличествоЗанятыхФайлов = КоличествоЗанятыхФайлов();
	Если Не КоличествоЗанятыхФайлов > 0 Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ТекущийПользователь = ПользователиКлиент.АвторизованныйПользователь();
	
	ПараметрыПрикладнойФормыПредупреждения = Новый Структура;
	ПараметрыПрикладнойФормыПредупреждения.Вставить("СообщениеВопрос",      НСтр("ru = 'Завершить работу с программой?'"));
	ПараметрыПрикладнойФормыПредупреждения.Вставить("СообщениеЗаголовок",   НСтр("ru = 'Следующие файлы заняты для редактирования:'"));
	ПараметрыПрикладнойФормыПредупреждения.Вставить("Заголовок",            НСтр("ru = 'Завершение работы'"));
	ПараметрыПрикладнойФормыПредупреждения.Вставить("Редактирует",          ТекущийПользователь);
	
	ПрикладнаяФормаПредупреждения = "Обработка.РаботаСФайлами.Форма.СписокЗанятыхСВопросом";
	Форма                         = "Обработка.РаботаСФайлами.Форма.РедактируемыеФайлы";
	
	ВозвращаемыеПараметры = Новый Структура;
	ВозвращаемыеПараметры.Вставить("ПрикладнаяФормаПредупреждения", ПрикладнаяФормаПредупреждения);
	ВозвращаемыеПараметры.Вставить("ПараметрыПрикладнойФормыПредупреждения", ПараметрыПрикладнойФормыПредупреждения);
	ВозвращаемыеПараметры.Вставить("Форма", Форма);
	ВозвращаемыеПараметры.Вставить("ПрикладнаяФормаПредупреждения", ПрикладнаяФормаПредупреждения);
	ВозвращаемыеПараметры.Вставить("КоличествоЗанятыхФайлов", КоличествоЗанятыхФайлов);
	
	Возврат ВозвращаемыеПараметры;
	
КонецФункции

// Возвращает значение параметра клиента КоличествоЗанятыхФайлов.
//
Функция КоличествоЗанятыхФайлов()
	
	Возврат СтандартныеПодсистемыКлиент.ПараметрКлиента("КоличествоЗанятыхФайлов");
	
КонецФункции

// Изменяет значение параметр клиента КоличествоЗанятыхФайлов.
//
Процедура ИзменитьКоличествоЗанятыхФайлов(ЗначениеИзменения = -1) Экспорт
	
	СтандартныеПодсистемыКлиент.УстановитьПараметрКлиента(
		"КоличествоЗанятыхФайлов", КоличествоЗанятыхФайлов() + ЗначениеИзменения);
	
КонецПроцедуры

// Возвращаемое значение:
//   Структура:
//     * Путь - Строка
//     * Размер - Число
//     * Версия - ОпределяемыйТип.ПрисоединенныйФайл
//     * ДатаПомещенияВРабочийКаталог - Дата
//
Функция ДанныеФайловВРабочемКаталоге()
	
	Возврат Новый Структура("Путь, Размер, Версия, ДатаПомещенияВРабочийКаталог");
	
КонецФункции

// Рекурсивный обход файлов в рабочем каталоге и сбор информации о них.
// Параметры:
//  Путь - Строка - путь рабочего каталога.
//  МассивФайлов - Массив - массив объектов "Файл".
//  ТаблицаФайлов - Массив из см. ДанныеФайловВРабочемКаталоге - массив структур файлов.
//
Процедура ОбходФайловТаблица(Путь, МассивФайлов, ТаблицаФайлов)
	
#Если Не ВебКлиент Тогда
	Перем Версия;
	Перем ДатаПомещения;
	
	ИмяКаталога = РабочийКаталогПользователя();
	
	Для Каждого ВыбранныйФайл Из МассивФайлов Цикл
		
		Если ВыбранныйФайл.ЭтоКаталог() Тогда
			НовыйПуть = Строка(Путь);
			НовыйПуть = НовыйПуть + ПолучитьРазделительПути();
			НовыйПуть = НовыйПуть + Строка(ВыбранныйФайл.Имя);
			МассивФайловВКаталоге = НайтиФайлы(НовыйПуть, ПолучитьМаскуВсеФайлы());
			
			Если МассивФайловВКаталоге.Количество() <> 0 Тогда
				ОбходФайловТаблица(НовыйПуть, МассивФайловВКаталоге, ТаблицаФайлов);
			КонецЕсли;
		
			Продолжить;
		КонецЕсли;
		
		// Временные файлы Word не удаляем из рабочего каталога.
		Если СтрНачинаетсяС(ВыбранныйФайл.Имя, "~") И ВыбранныйФайл.ПолучитьНевидимость() Тогда
			Продолжить;
		КонецЕсли;
		
		ОтносительныйПуть = Сред(ВыбранныйФайл.ПолноеИмя, СтрДлина(ИмяКаталога) + 1);
		
		// Если не найдем на компьютере, то минимальная дата будет самой старой,
		// и удалится при очистке из рабочего каталога самых старых файлов.
		ДатаПомещения = Дата('00010101');
		
		НайденныеСвойства = РаботаСФайламиСлужебныйВызовСервера.НайтиВРегистреПоПути(ОтносительныйПуть);
		ФайлЕстьВРегистре = НайденныеСвойства.ФайлЕстьВРегистре;
		Версия            = НайденныеСвойства.Файл;
		ДатаПомещения     = ?(ФайлЕстьВРегистре, НайденныеСвойства.ДатаПомещения, ДатаПомещения);
		
		Если ФайлЕстьВРегистре Тогда
			РедактируетТекущийПользователь = РаботаСФайламиСлужебныйВызовСервера.ПолучитьРедактируетТекущийПользователь(Версия);
			
			// Если не занят текущим пользователем, можно удалить.
			Если Не РедактируетТекущийПользователь Тогда
				Запись = ДанныеФайловВРабочемКаталоге();
				Запись.Путь = ОтносительныйПуть;
				Запись.Размер = ВыбранныйФайл.Размер();
				Запись.Версия = Версия;
				Запись.ДатаПомещенияВРабочийКаталог = ДатаПомещения;
				ТаблицаФайлов.Добавить(Запись);
			КонецЕсли;
		Иначе
			Запись = ДанныеФайловВРабочемКаталоге();
			Запись.Путь = ОтносительныйПуть;
			Запись.Размер = ВыбранныйФайл.Размер();
			Запись.Версия = Версия;
			Запись.ДатаПомещенияВРабочийКаталог = ДатаПомещения;
			ТаблицаФайлов.Добавить(Запись);
		КонецЕсли;
		
	КонецЦикла;
#КонецЕсли
	
КонецПроцедуры

// Получает относительный путь к файлу в рабочем каталоге - если есть в регистре сведений - оттуда,
// если нет - сгенерируем и запишем в регистр сведений.
//
// Параметры:
//  ДанныеФайла  - Структура
//
// Возвращаемое значение:
//   Строка
//
Функция ПолучитьПутьФайлаВРабочемКаталоге(ДанныеФайла)
	
	ПутьДляВозврата = "";
	ПолноеИмяФайла = "";
	ИмяКаталога = РабочийКаталогПользователя();
	
	ПолноеИмяФайла = ДанныеФайла.ПолноеИмяФайлаВРабочемКаталоге;
	
	Если ПолноеИмяФайла <> "" Тогда
		ФайлНаДиске = Новый Файл(ПолноеИмяФайла);
		Если ФайлНаДиске.Существует() Тогда
			Возврат ПолноеИмяФайла;
		КонецЕсли;
	КонецЕсли;
	
	ИмяФайла = ДанныеФайла.ПолноеНаименованиеВерсии;
	Расширение = ДанныеФайла.Расширение;
	Если Не ПустаяСтрока(Расширение) Тогда 
		ИмяФайла = ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(ИмяФайла, Расширение);
	КонецЕсли;
	
	ОбщегоНазначенияСлужебныйКлиент.СократитьИмяФайла(ИмяФайла);
	
	ПолноеИмяФайла = "";
	Если Не ПустаяСтрока(ИмяФайла) Тогда
		Если Не ПустаяСтрока(ДанныеФайла.РабочийКаталогВладельца) Тогда
			ПолноеИмяФайла = ДанныеФайла.РабочийКаталогВладельца + ДанныеФайла.ПолноеНаименованиеВерсии + "." + ДанныеФайла.Расширение;
		Иначе
			ПолноеИмяФайла = РаботаСФайламиСлужебныйКлиентСервер.УникальноеИмяСПутем(ИмяКаталога, ИмяФайла);
		КонецЕсли;
	КонецЕсли;
	
	Если ПустаяСтрока(ИмяФайла) Тогда
		Возврат "";
	КонецЕсли;
	
	// Запишем в регистр имя файла.
	НаЧтение = Истина;
	ВРабочемКаталогеВладельца = ДанныеФайла.РабочийКаталогВладельца <> "";
	РаботаСФайламиСлужебныйВызовСервера.ЗаписатьПолноеИмяФайлаВРегистр(ДанныеФайла.Версия, ПолноеИмяФайла, НаЧтение, ВРабочемКаталогеВладельца);
	
	Если ДанныеФайла.РабочийКаталогВладельца = "" Тогда
		ПутьДляВозврата = ИмяКаталога + ПолноеИмяФайла;
	Иначе
		ПутьДляВозврата = ПолноеИмяФайла;
	КонецЕсли;
	
	Возврат ПутьДляВозврата;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// ВСПОМОГАТЕЛЬНЫЕ ПРОЦЕДУРЫ И ФУНКЦИИ

// Возвращаемое значение:
//   см. РаботаСФайлами.НастройкиРаботыСФайлами
//
Функция ПерсональныеНастройкиРаботыСФайлами() Экспорт
	
	Возврат СтандартныеПодсистемыКлиент.ПараметрыРаботыКлиента().ПерсональныеНастройкиРаботыСФайлами;
	
КонецФункции

// Возвращает структуру, содержащую различные персональные настройки.
Функция ОбщиеНастройкиРаботыСФайлами()
	
	ОбщиеНастройки = СтандартныеПодсистемыКлиент.ПараметрыРаботыКлиента().ОбщиеНастройкиРаботыСФайлами;
	
	// Проверка и обновление настроек сохраненных на сервере,
	// которые вычисляются на клиенте.
	
	Возврат ОбщиеНастройки;
	
КонецФункции

// Параметры:
//  ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//  ТекущаяВерсия  - СправочникСсылка.ВерсииФайлов
//  ПолноеИмяФайла - Строка - имя файла с путем.
//  ВРабочемКаталогеНаЧтение - Булево - файл помещен на чтение.
//  ВРабочемКаталогеВладельца - Булево - файл в рабочем каталоге владельца (а не в основном рабочем каталоге).
//
// Возвращаемое значение:
//  Булево
//
Функция ФайлНаходитсяВЛокальномКэшеФайлов(ДанныеФайла, ТекущаяВерсия, ПолноеИмяФайла, ВРабочемКаталогеНаЧтение, 
	ВРабочемКаталогеВладельца)
	
	ПолноеИмяФайла = "";
	
	// Если это активная версия - берем из ДанныеФайла.
	Если ДанныеФайла <> Неопределено И ДанныеФайла.ТекущаяВерсия = ТекущаяВерсия Тогда
		ПолноеИмяФайла = ДанныеФайла.ПолноеИмяФайлаВРабочемКаталоге;
		ВРабочемКаталогеНаЧтение = ДанныеФайла.ВРабочемКаталогеНаЧтение;
	Иначе
		ВРабочемКаталогеНаЧтение = Истина;
		ИмяКаталога = РабочийКаталогПользователя();
		ПолноеИмяФайла = РаботаСФайламиСлужебныйВызовСервера.ПолноеИмяФайлаВРабочемКаталоге(ТекущаяВерсия, 
			ИмяКаталога, ВРабочемКаталогеНаЧтение, ВРабочемКаталогеВладельца);
	КонецЕсли;
	
	Если ПолноеИмяФайла <> "" Тогда
		ФайлНаДиске = Новый Файл(ПолноеИмяФайла);
		Если ФайлНаДиске.Существует() Тогда
			Возврат Истина;
		Иначе
			ПолноеИмяФайла = "";
			РаботаСФайламиСлужебныйВызовСервера.УдалитьИзРегистра(ТекущаяВерсия);
		КонецЕсли;
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

// Выбрать путь к рабочему каталогу.
// Параметры:
//  ИмяКаталога  - Строка - прежнее имя каталога.
//  Заголовок  - Строка - заголовок формы выбора пути каталога.
//  РабочийКаталогВладельца - Строка-  рабочий каталог владельца.
//
// Возвращаемое значение:
//   Булево  - успешно ли выполнена операция.
//
Функция ВыбратьПутьКРабочемуКаталогу(ИмяКаталога, Заголовок, РабочийКаталогВладельца) Экспорт
	
	Режим = РежимДиалогаВыбораФайла.ВыборКаталога;
	ДиалогОткрытияФайла = Новый ДиалогВыбораФайла(Режим);
	ДиалогОткрытияФайла.ПолноеИмяФайла = "";
	ДиалогОткрытияФайла.Каталог = ИмяКаталога;
	ДиалогОткрытияФайла.МножественныйВыбор = Ложь;
	ДиалогОткрытияФайла.Заголовок = Заголовок;
	
	Если ДиалогОткрытияФайла.Выбрать() Тогда
		
		ИмяКаталога = ДиалогОткрытияФайла.Каталог;
		ИмяКаталога = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(ИмяКаталога);
		
		// Создать каталог для файлов
		Попытка
			СоздатьКаталог(ИмяКаталога);
			ИмяКаталогаТестовое = ИмяКаталога + "ПроверкаДоступа\";
			СоздатьКаталог(ИмяКаталогаТестовое);
			УдалитьФайлы(ИмяКаталогаТестовое);
		Исключение
			ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
				"Предупреждение", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()),, Истина);

			// Нет прав на создание каталога, или такой путь отсутствует.
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Неверный путь или отсутствуют права на запись в каталог
				           |""%1"".'"),
				ИмяКаталога);
			ПоказатьПредупреждение(, ТекстОшибки);
			Возврат Ложь;
		КонецПопытки;
		
		Если РабочийКаталогВладельца = Ложь Тогда
#Если Не ВебКлиент Тогда
			МассивФайловВКаталоге = НайтиФайлы(ИмяКаталога, ПолучитьМаскуВсеФайлы());
			Если МассивФайловВКаталоге.Количество() <> 0 Тогда
				ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'В выбранном рабочем каталоге
					           |""%1""
					           |уже есть файлы.
					           |
					           |Выберите другой каталог.'"),
					ИмяКаталога);
				ПоказатьПредупреждение(, ТекстОшибки);
				Возврат Ложь;
			КонецЕсли;
#КонецЕсли
		КонецЕсли;
		
		Возврат Истина;
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

// Перерегистрировать В рабочем каталоге с другим флагом НаЧтение.
// Параметры:
//  ТекущаяВерсия  - СправочникСсылка.ВерсииФайлов - версия файла.
//  ПолноеИмяФайла - Строка - полное имя файла.
//  НаЧтение - Булево - файл помещен на чтение.
//  ВРабочемКаталогеВладельца - Булево - файл в рабочем каталоге владельца (а не в основном рабочем каталоге).
//
Процедура ПеререгистрироватьВРабочемКаталоге(ТекущаяВерсия, ПолноеИмяФайла, НаЧтение, ВРабочемКаталогеВладельца)
	
	ИмяКаталога = РабочийКаталогПользователя();
	
	РаботаСФайламиСлужебныйВызовСервера.ЗанестиИнформациюФайлаВРегистр(ТекущаяВерсия, ПолноеИмяФайла, ИмяКаталога, НаЧтение, 0, ВРабочемКаталогеВладельца);
	Файл = Новый Файл(ПолноеИмяФайла);
	Файл.УстановитьТолькоЧтение(НаЧтение);
	
КонецПроцедуры

// Обход Файлов рекурсивный - для определения размера файлов.
// Параметры:
//  МассивФайлов - Массив - массив объектов "Файл".
//  МассивСлишкомБольшихФайлов - Массив - массив файлов.
//  Рекурсивно - Булево - рекурсивно обходить подкаталоги.
//  КоличествоСуммарное - Число - количество суммарное импортированных файлов.
//  ПсевдоФайловаяСистема - Соответствие - эмуляция файловой системы - для строки (каталога) возвращает массив строк
//                                         (подкаталоги и файлы).
//
Процедура НайтиСлишкомБольшиеФайлы(
				МассивФайлов,
				МассивСлишкомБольшихФайлов,
				Рекурсивно,
				КоличествоСуммарное,
				Знач ПсевдоФайловаяСистема) 
	
	МаксРазмерФайла = ОбщиеНастройкиРаботыСФайлами().МаксимальныйРазмерФайла;
	
	Для Каждого ВыбранныйФайл Из МассивФайлов Цикл
		
		Если ВыбранныйФайл.Существует() Тогда
			
			Если ВыбранныйФайл.Расширение = ".lnk" Тогда
				ВыбранныйФайл = РазыменоватьLnkФайл(ВыбранныйФайл);
			КонецЕсли;
			
			Если ВыбранныйФайл.ЭтоКаталог() Тогда
				
				Если Рекурсивно Тогда
					НовыйПуть = Строка(ВыбранныйФайл.Путь);
					НовыйПуть = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(НовыйПуть);
					НовыйПуть = НовыйПуть + Строка(ВыбранныйФайл.Имя);
					МассивФайловВКаталоге = НайтиФайлыПсевдо(ПсевдоФайловаяСистема, НовыйПуть);
					
					// Рекурсия
					Если МассивФайловВКаталоге.Количество() <> 0 Тогда
						НайтиСлишкомБольшиеФайлы(МассивФайловВКаталоге, МассивСлишкомБольшихФайлов, Рекурсивно, КоличествоСуммарное, ПсевдоФайловаяСистема);
					КонецЕсли;
				КонецЕсли;
			
				Продолжить;
			КонецЕсли;
			
			КоличествоСуммарное = КоличествоСуммарное + 1;
			
			// Размер файла слишком большой.
			Если ВыбранныйФайл.Размер() > МаксРазмерФайла Тогда
				МассивСлишкомБольшихФайлов.Добавить(ВыбранныйФайл.ПолноеИмя);
				Продолжить;
			КонецЕсли;
		
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

// Возвращает массив файлов, эмулируя работу НайтиФайлы - но не по файловой системе, а по Соответствию
//  если ПсевдоФайловаяСистема пуста - работает с файловой системой.
//
Функция НайтиФайлыПсевдо(Знач ПсевдоФайловаяСистема, Путь)
	
	Если ПсевдоФайловаяСистема.Количество() = 0 Тогда
		Файлы = НайтиФайлы(Путь, ПолучитьМаскуВсеФайлы());
		Возврат Файлы;
	КонецЕсли;
	
	Файлы = Новый Массив;
	
	ЗначениеНайденное = ПсевдоФайловаяСистема.Получить(Строка(Путь));
	Если ЗначениеНайденное <> Неопределено Тогда
		Для Каждого ИмяФайла Из ЗначениеНайденное Цикл
			ФайлИзСписка = Новый Файл(ИмяФайла);
			Файлы.Добавить(ФайлИзСписка);
		КонецЦикла;
	КонецЕсли;
	
	Возврат Файлы;
	
КонецФункции

// Разыменовать lnk файл
// Параметры:
//  ВыбранныйФайл - Файл - объект типа Файл.
//
// Возвращаемое значение:
//   Строка - на что ссылается lnk  файл.
//
Функция РазыменоватьLnkФайл(ВыбранныйФайл)
	
#Если Не ВебКлиент И НЕ МобильныйКлиент Тогда
	ПриложениеShell = Новый COMОбъект("shell.application");
	ПолныйПуть = ПриложениеShell.NameSpace(ВыбранныйФайл.Путь);// Полный (только) путь на lnk-файл.
	ИмяФайла = ПолныйПуть.items().item(ВыбранныйФайл.Имя); // только имя lnk-файла
	Ссылка = ИмяФайла.GetLink();
	Возврат Новый Файл(Ссылка.path);
#КонецЕсли
	
	Возврат ВыбранныйФайл;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Сравнение версий и файлов.
// Сравнивает 2 файла (txt doc doc odt mxl) с помощью MS Office, OpenOffice, программно для табличных документов.
//
Процедура СравнитьФайлы(ИдентификаторФормы, ПервыйФайл, ВторойФайл, Расширение, ВладелецВерсии = Неопределено) Экспорт
	
	СпособСравненияВерсийФайлов = Неопределено;
	
	РасширениеПоддерживается = (
		Расширение = "txt"
		Или Расширение = "md"
		Или Расширение = "doc"
		Или Расширение = "docx"
		Или Расширение = "rtf"
		Или Расширение = "htm"
		Или Расширение = "html"
		Или Расширение = "mxl"
		Или Расширение = "odt");
	
	Если Не РасширениеПоддерживается Тогда
		ТекстПредупреждения =
		НСтр("ru = 'Сравнение файлов возможно только для следующих типов:
			|   Текстовый документ (.txt, .md)
			|   Документ формата RTF (.rtf)
			|   Документ Microsoft Word (.doc, .docx)
			|   Документ HTML (.html, .htm)
			|   Табличный документ (.mxl)
			|   Текстовый документ OpenDocument (.odt)'");
		ПоказатьПредупреждение(, ТекстПредупреждения);
		Возврат;
	КонецЕсли;
	
	Если Расширение = "odt" Тогда
		СпособСравненияВерсийФайлов = "OpenOfficeOrgWriter";
	ИначеЕсли Расширение = "htm" ИЛИ Расширение = "html" Тогда
		СпособСравненияВерсийФайлов = "MicrosoftOfficeWord";
	ИначеЕсли Расширение = "mxl" Тогда
		СпособСравненияВерсийФайлов = "СравнениеТабличныхДокументов";
	КонецЕсли;
	
	ПараметрыВыполнения = Новый Структура;
	ПараметрыВыполнения.Вставить("СпособСравненияВерсийФайлов", СпособСравненияВерсийФайлов);
	ПараметрыВыполнения.Вставить("ТекущийШаг",              "Шаг1ВыборСпособаСравненияВерсий");
	ПараметрыВыполнения.Вставить("ДанныеФайла1",            Неопределено);
	ПараметрыВыполнения.Вставить("ДанныеФайла2",            Неопределено);
	ПараметрыВыполнения.Вставить("Результат1",              Неопределено);
	ПараметрыВыполнения.Вставить("Результат2",              Неопределено);
	ПараметрыВыполнения.Вставить("ПолноеИмяФайла1",         "");
	ПараметрыВыполнения.Вставить("ПолноеИмяФайла2",         "");
	ПараметрыВыполнения.Вставить("УникальныйИдентификатор", ИдентификаторФормы);
	ПараметрыВыполнения.Вставить("Ссылка1",                 ПервыйФайл);
	ПараметрыВыполнения.Вставить("Ссылка2",                 ВторойФайл);
	ПараметрыВыполнения.Вставить("ВладелецВерсии",          ВладелецВерсии);
	СравнитьФайлыСлужебный(ПараметрыВыполнения);
	
КонецПроцедуры

Процедура СравнитьФайлыСлужебный(ПараметрыВыполнения)
	
	Если ПараметрыВыполнения.ТекущийШаг = "Шаг1ВыборСпособаСравненияВерсий" Тогда
		Если ПараметрыВыполнения.СпособСравненияВерсийФайлов = Неопределено Тогда
			ПерсональныеНастройки = ПерсональныеНастройкиРаботыСФайлами();
			ПараметрыВыполнения.СпособСравненияВерсийФайлов = ПерсональныеНастройки.СпособСравненияВерсийФайлов;
			Если ПараметрыВыполнения.СпособСравненияВерсийФайлов = Неопределено Тогда
				Обработчик = Новый ОписаниеОповещения("СравнитьФайлыОбработкаРезультата", ЭтотОбъект, ПараметрыВыполнения);
				ОткрытьФорму("Обработка.РаботаСФайлами.Форма.ВыборСпособаСравненияВерсий",, ЭтотОбъект,,,, Обработчик);
				Возврат;
			КонецЕсли;
		КонецЕсли;
		ПараметрыВыполнения.ТекущийШаг = "Шаг2ПолучитьДанныеФайлов";
	КонецЕсли;
	
	Если ПараметрыВыполнения.ТекущийШаг = "Шаг2ПолучитьДанныеФайлов" Тогда
		
		Если ПараметрыВыполнения.Свойство("ВладелецВерсии") И ЗначениеЗаполнено(ПараметрыВыполнения.ВладелецВерсии) Тогда
			ПараметрыВыполнения.ДанныеФайла1 = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаДляОткрытия(
				ПараметрыВыполнения.ВладелецВерсии, ПараметрыВыполнения.Ссылка1, ПараметрыВыполнения.УникальныйИдентификатор);
			ПараметрыВыполнения.ДанныеФайла2 = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаДляОткрытия(
				ПараметрыВыполнения.ВладелецВерсии, ПараметрыВыполнения.Ссылка2, ПараметрыВыполнения.УникальныйИдентификатор);
		Иначе
			ПараметрыВыполнения.ДанныеФайла1 = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаДляОткрытия(
				ПараметрыВыполнения.Ссылка1, Неопределено, ПараметрыВыполнения.УникальныйИдентификатор);
			ПараметрыВыполнения.ДанныеФайла2 = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаДляОткрытия(
				ПараметрыВыполнения.Ссылка2, Неопределено, ПараметрыВыполнения.УникальныйИдентификатор);
		КонецЕсли;
		
		ПараметрыВыполнения.ТекущийШаг = "Шаг3ПолучитьПервыйФайл";
	КонецЕсли;
	
	Если ПараметрыВыполнения.ТекущийШаг = "Шаг3ПолучитьПервыйФайл" Тогда
		Обработчик = Новый ОписаниеОповещения("СравнитьФайлыОбработкаРезультата", ЭтотОбъект, ПараметрыВыполнения);
		ПолучитьФайлВерсииВРабочийКаталог(Обработчик, ПараметрыВыполнения.ДанныеФайла1, 
			ПараметрыВыполнения.ПолноеИмяФайла1);
		Возврат;
	КонецЕсли;
	
	Если ПараметрыВыполнения.ТекущийШаг = "Шаг4ПолучитьВторойФайл" Тогда
		Обработчик = Новый ОписаниеОповещения("СравнитьФайлыОбработкаРезультата", ЭтотОбъект, ПараметрыВыполнения);
		ПолучитьФайлВерсииВРабочийКаталог(Обработчик, ПараметрыВыполнения.ДанныеФайла2, 
			ПараметрыВыполнения.ПолноеИмяФайла2);
		Возврат;
	КонецЕсли;
	
	Если ПараметрыВыполнения.ТекущийШаг = "Шаг5СравнитьФайлы" Тогда
		Если Не ПараметрыВыполнения.Результат1 Или Не ПараметрыВыполнения.Результат2 Тогда
			Возврат;
		КонецЕсли;	
		
		ШаблонЗаголовкаФайла = НСтр("ru = '%1 (версия № %2)'");
		ДанныеПервогоФайла = ПараметрыВыполнения.ДанныеФайла1; // см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
		ИмяФайла1 = ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(ДанныеПервогоФайла.ПолноеНаименованиеВерсии,
			ДанныеПервогоФайла.Расширение);
		ЗаголовокФайла1 = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонЗаголовкаФайла,
			ИмяФайла1, ПараметрыВыполнения.ДанныеФайла1.НомерВерсии);
			
		ДанныеВторогоФайла = ПараметрыВыполнения.ДанныеФайла2; // см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
		ИмяФайла2 = ОбщегоНазначенияКлиентСервер.ПолучитьИмяСРасширением(ДанныеВторогоФайла.ПолноеНаименованиеВерсии,
			ДанныеВторогоФайла.Расширение);
		ЗаголовокФайла2 = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонЗаголовкаФайла,
			ИмяФайла2, ПараметрыВыполнения.ДанныеФайла2.НомерВерсии);
			
		Если ПараметрыВыполнения.ДанныеФайла1.НомерВерсии < ПараметрыВыполнения.ДанныеФайла2.НомерВерсии Тогда
			ПолноеИмяФайлаСлева  = ПараметрыВыполнения.ПолноеИмяФайла1;
			ЗаголовокФайлаСлева  = ЗаголовокФайла1;
			ПолноеИмяФайлаСправа = ПараметрыВыполнения.ПолноеИмяФайла2;
			ЗаголовокФайлаСправа = ЗаголовокФайла2;
		Иначе
			ПолноеИмяФайлаСлева  = ПараметрыВыполнения.ПолноеИмяФайла2;
			ЗаголовокФайлаСлева  = ЗаголовокФайла2;
			ПолноеИмяФайлаСправа = ПараметрыВыполнения.ПолноеИмяФайла1;
			ЗаголовокФайлаСправа = ЗаголовокФайла1;
		КонецЕсли;
			
		ВыполнитьСравнениеФайлов(ПолноеИмяФайлаСлева, ПолноеИмяФайлаСправа,
			ПараметрыВыполнения.СпособСравненияВерсийФайлов,
			ЗаголовокФайлаСлева, ЗаголовокФайлаСправа);
	КонецЕсли;
	
КонецПроцедуры

Процедура СравнитьФайлыОбработкаРезультата(Результат, ПараметрыВыполнения) Экспорт

	Если ПараметрыВыполнения.ТекущийШаг = "Шаг1ВыборСпособаСравненияВерсий" Тогда
		Если Результат <> КодВозвратаДиалога.ОК Тогда
			Возврат;
		КонецЕсли;
		
		ПерсональныеНастройки = ПерсональныеНастройкиРаботыСФайлами();
		ПараметрыВыполнения.СпособСравненияВерсийФайлов = ПерсональныеНастройки.СпособСравненияВерсийФайлов;
		Если ПараметрыВыполнения.СпособСравненияВерсийФайлов = Неопределено Тогда
			Возврат;
		КонецЕсли;
		ПараметрыВыполнения.ТекущийШаг = "Шаг2ПолучитьДанныеФайлов";
		
	ИначеЕсли ПараметрыВыполнения.ТекущийШаг = "Шаг3ПолучитьПервыйФайл" Тогда
		ПараметрыВыполнения.Результат1      = Результат.ФайлПолучен;
		ПараметрыВыполнения.ПолноеИмяФайла1 = Результат.ПолноеИмяФайла;
		ПараметрыВыполнения.ТекущийШаг = "Шаг4ПолучитьВторойФайл";
		
	ИначеЕсли ПараметрыВыполнения.ТекущийШаг = "Шаг4ПолучитьВторойФайл" Тогда
		ПараметрыВыполнения.Результат2      = Результат.ФайлПолучен;
		ПараметрыВыполнения.ПолноеИмяФайла2 = Результат.ПолноеИмяФайла;
		ПараметрыВыполнения.ТекущийШаг = "Шаг5СравнитьФайлы";
	КонецЕсли;
	
	СравнитьФайлыСлужебный(ПараметрыВыполнения);

КонецПроцедуры

Процедура ВыполнитьСравнениеФайлов(ПутьКФайлу1, ПутьКФайлу2, СпособСравненияВерсийФайлов, ЗаголовокЛевый = "", ЗаголовокПравый = "") Экспорт
	
	Попытка
		Если СпособСравненияВерсийФайлов = "MicrosoftOfficeWord" Тогда
			СравнитьФайлыMicrosoftWord(ПутьКФайлу1, ПутьКФайлу2);
		ИначеЕсли СпособСравненияВерсийФайлов = "OpenOfficeOrgWriter" Тогда 
			СравнитьФайлыOpenOfficeOrgWriter(ПутьКФайлу1, ПутьКФайлу2);
		ИначеЕсли СпособСравненияВерсийФайлов = "СравнениеТабличныхДокументов" Тогда
			СравнитьТабличныеДокументы(ПутьКФайлу1, ПутьКФайлу2, ЗаголовокЛевый, ЗаголовокПравый);
		КонецЕсли;
		
	Исключение
		СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось сравнить файлы по причине: %1'"),
			ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
		ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(
			НСтр("ru = 'Файлы.Сравнение файлов'", ОбщегоНазначенияКлиент.КодОсновногоЯзыка()),
			"Ошибка", СообщениеОбОшибке, , Истина);
		ВызватьИсключение СообщениеОбОшибке;
	КонецПопытки;
	
КонецПроцедуры

Процедура СравнитьФайлыOpenOfficeOrgWriter(Знач ПутьКФайлу1, Знач ПутьКФайлу2)
	
#Если Не ВебКлиент И НЕ МобильныйКлиент Тогда
	
	// Снимем readonly - иначе не сработает.
	Файл1 = Новый Файл(ПутьКФайлу1);
	Файл1.УстановитьТолькоЧтение(Ложь);
	
	Файл2 = Новый Файл(ПутьКФайлу2);
	Файл2.УстановитьТолькоЧтение(Ложь);
	
	// Открыть OpenOffice
	Попытка
		ОбъектServiceManager = Новый COMОбъект("com.sun.star.ServiceManager");
		ОбъектDesktop = ОбъектServiceManager.createInstance("com.sun.star.frame.Desktop");
		ОбъектDispatcherHelper = ОбъектServiceManager.createInstance("com.sun.star.frame.DispatchHelper");
	Исключение
		ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(
			НСтр("ru = 'Файлы.Сравнение файлов'", ОбщегоНазначенияКлиент.КодОсновногоЯзыка()),
			"Ошибка", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()),, Истина);
		ВызватьИсключение ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()) + Символы.ПС 
			+ НСтр("ru = 'Установите (переустановите) приложение OpenOffice.org Writer.'");
	КонецПопытки;	
	
	// Параметры открытия: отключение исполнения макросов.
	ПараметрыДокумента = Новый COMSafeArray("VT_VARIANT", 1);
	РежимЗапуска = ПрисвоитьЗначениеСвойству(ОбъектServiceManager,
		"MacroExecutionMode",
		0); // const short NEVER_EXECUTE = 0
	ПараметрыДокумента.SetValue(0, РежимЗапуска);
	
	// Открыть документ OpenOffice.
	ОбъектDesktop.loadComponentFromURL(ПреобразоватьВURL(ПутьКФайлу2), "_blank", 0, ПараметрыДокумента);
	
	ТекущееОкно = ОбъектDesktop.getCurrentFrame();
	
	// Установить показ изменений.
	ПараметрыСравнения = Новый COMSafeArray("VT_VARIANT", 1);
	ПараметрыСравнения.SetValue(0, ПрисвоитьЗначениеСвойству(ОбъектServiceManager, "ShowTrackedChanges", Истина));
	ОбъектDispatcherHelper.executeDispatch(ТекущееОкно, ".uno:ShowTrackedChanges", "", 0, ПараметрыСравнения);
	
	// Сравнить с документом.
	ПараметрыВызова = Новый COMSafeArray("VT_VARIANT", 1);
	ПараметрыВызова.SetValue(0, ПрисвоитьЗначениеСвойству(ОбъектServiceManager, "URL", ПреобразоватьВURL(ПутьКФайлу1)));
	ОбъектDispatcherHelper.executeDispatch(ТекущееОкно, ".uno:CompareDocuments", "", 0, ПараметрыВызова);

#КонецЕсли

КонецПроцедуры

Процедура СравнитьФайлыMicrosoftWord(ПутьКФайлу1, ПутьКФайлу2)
	
#Если Не ВебКлиент И НЕ МобильныйКлиент Тогда
	
	Попытка
		ОбъектWord = Новый COMОбъект("Word.Application");
	Исключение
		ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(
			НСтр("ru = 'Файлы.Сравнение файлов'", ОбщегоНазначенияКлиент.КодОсновногоЯзыка()),
			"Ошибка", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()),, Истина);
		ВызватьИсключение ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()) + Символы.ПС 
			+ НСтр("ru = 'Установите (переустановите) приложение Microsoft Word.'");
	КонецПопытки;	
	ОбъектWord.Visible = 0;
	ОбъектWord.WordBasic.DisableAutoMacros(1);
	
	Документ = ОбъектWord.Documents.Open(ПутьКФайлу1);
	Попытка
		ОбъектWord.ActiveWindow.ActivePane.View.Type = 1; // wdNormalView = 1
		Документ.Merge(ПутьКФайлу2, 2, 0, 0); // MergeTarget:=wdMergeTargetSelected, DetectFormatChanges:=False, UseFormattingFrom:=wdFormattingFromCurrent
	Исключение
		ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(
			НСтр("ru = 'Файлы.Сравнение файлов'", ОбщегоНазначенияКлиент.КодОсновногоЯзыка()),
			"Ошибка", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()),, Истина);
		ВызватьИсключение ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
	КонецПопытки;	
	
	ОбъектWord.Visible = 1;
	ОбъектWord.Activate();
	
	Документ.Close();

#КонецЕсли

КонецПроцедуры

Процедура СравнитьТабличныеДокументы(ПутьКФайлу1, ПутьКФайлу2, ЗаголовокЛевый, ЗаголовокПравый)
	
	ПомещаемыеФайлы = Новый Массив;
	ПомещаемыеФайлы.Добавить(Новый ОписаниеПередаваемогоФайла(ПутьКФайлу1));
	ПомещаемыеФайлы.Добавить(Новый ОписаниеПередаваемогоФайла(ПутьКФайлу2));
	
	ПомещенныеФайлы = Новый Массив;
	Если Не ПоместитьФайлы(ПомещаемыеФайлы, ПомещенныеФайлы, , Ложь) Тогда
		Возврат;
	КонецЕсли;
	ТабличныйДокументЛевый  = ПомещенныеФайлы[0].Хранение;
	ТабличныйДокументПравый = ПомещенныеФайлы[1].Хранение;
	
	СравниваемыеДокументы = Новый Структура("Левый, Правый", ТабличныйДокументЛевый, ТабличныйДокументПравый);
	АдресТабличныхДокументов = ПоместитьВоВременноеХранилище(СравниваемыеДокументы, Неопределено);
	
	ПараметрыОткрытияФормы = Новый Структура;
	ПараметрыОткрытияФормы.Вставить("АдресТабличныхДокументов", АдресТабличныхДокументов);
	ПараметрыОткрытияФормы.Вставить("ЗаголовокЛевый", ЗаголовокЛевый);
	ПараметрыОткрытияФормы.Вставить("ЗаголовокПравый", ЗаголовокПравый);
	ПараметрыОткрытияФормы.Вставить("Заголовок", СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Сравнение %1 с %2'"), ЗаголовокЛевый, ЗаголовокПравый));
	ОткрытьФорму("ОбщаяФорма.СравнениеТабличныхДокументов", ПараметрыОткрытияФормы, ЭтотОбъект);
	
КонецПроцедуры

// Функция преобразует Windows имя файла в URL OpenOffice.
Функция ПреобразоватьВURL(ИмяФайла)
	
	Возврат "file:///" + СтрЗаменить(ИмяФайла, "\", "/");
	
КонецФункции

// Создание структуры для параметров OpenOffice.
Функция ПрисвоитьЗначениеСвойству(Объект, ИмяСвойства, ЗначениеСвойства)
	
	Свойства = Объект.Bridge_GetStruct("com.sun.star.beans.PropertyValue");
	Свойства.Name = ИмяСвойства;
	Свойства.Value = ЗначениеСвойства;
	
	Возврат Свойства;
	
КонецФункции

// Возвращает каталог данных пользователя внутри стандартного каталога данных приложения.
// Этот каталог может использоваться для хранения файлов, захваченных текущим пользователем.
// Для работы метода на веб-клиенте необходимо предварительно подключить расширение для работы с 1С:Предприятием.
//
Функция КаталогДанныхПользователя()
	
	#Если ВебКлиент Или МобильныйКлиент Тогда
		Возврат РабочийКаталогДанныхПользователя();
	#Иначе
		Если Не ОбщегоНазначенияКлиент.ЭтоWindowsКлиент() Тогда
			Возврат РабочийКаталогДанныхПользователя();
		Иначе
			Оболочка = Новый COMОбъект("WScript.Shell");
			КаталогДанныхПользователя = Оболочка.ExpandEnvironmentStrings("%APPDATA%");
			Возврат ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(КаталогДанныхПользователя);
		КонецЕсли;
	#КонецЕсли
	
КонецФункции

// Открывает форму перетаскивания.
Процедура ОткрытьФормуПеретаскиванияИзвне(ПапкаДляДобавления, МассивИменФайлов) Экспорт
	
	ПараметрыФормы = Новый Структура;
	ПараметрыФормы.Вставить("ПапкаДляДобавления", ПапкаДляДобавления);
	ПараметрыФормы.Вставить("МассивИменФайлов",   МассивИменФайлов);
	
	ОткрытьФорму("Справочник.Файлы.Форма.ФормаПеретаскивания", ПараметрыФормы);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Служебные процедуры и функции для асинхронных методов.
//
// Общее описание параметров:
//   Обработчик - ОписаниеОповещения, Неопределено, Структура - Процедура-обработчик асинхронного метода.
//       * Неопределено       - Обработка не требуется.
//       * ОписаниеОповещения - Описание процедуры-обработчика.
//     В редких случаях может потребоваться прерывать выполнение кода только тогда,
//     когда необходимо показать асинхронный диалог (в циклах например).
//     В таких случаях в Обработчик передается Структура параметров вызывающего кода
//     с обязательным ключом АсинхронныйДиалог,
//     который используется при прерывании кода и открытии асинхронного диалога:
//       * Структура - Структура параметров вызывающего кода.
//           ** АсинхронныйДиалог - Структура - 
//               *** Открыт       - Булево - Истина если диалог был открыт.
//               *** ИмяПроцедуры - Строка - Имя процедуры обработчика вызывающего кода.
//               *** Модуль       - ОбщийМодуль, ФормаКлиентскогоПриложения - Модуль обработчика вызывающего кода.
//             В этом случае ОписаниеОповещения формируется из ключей "ИмяПроцедуры" и "Модуль".
//             Внимание. Не все асинхронные процедуры поддерживают передачу типа Структура. Читайте состав типов.
//
//   Результат - Произвольный - Результат, который необходимо вернуть в Обработчик.
//

// Показывает окно предупреждение, а после его закрытия вызывает обработчик с заданным результатом.
Процедура ВернутьРезультатПослеПоказаПредупреждения(Обработчик, ТекстПредупреждения, Результат)
	
	Если Обработчик <> Неопределено Тогда
		ПараметрыОбработчика = Новый Структура;
		ПараметрыОбработчика.Вставить("Обработчик", ОбработчикЗавершения(Обработчик));
		ПараметрыОбработчика.Вставить("Результат", Результат);
		Обработчик = Новый ОписаниеОповещения("ВернутьРезультатПослеЗакрытияПростогоДиалога", ЭтотОбъект, ПараметрыОбработчика);
		ПоказатьПредупреждение(Обработчик, ТекстПредупреждения);
	Иначе
		ПоказатьПредупреждение(, ТекстПредупреждения);
	КонецЕсли;
	
КонецПроцедуры

// Показывает окно просмотра значения, а после его закрытия вызывает обработчик с заданным результатом.
Процедура ВернутьРезультатПослеПоказаЗначения(Обработчик, Значение, Результат)
	
	Если Обработчик <> Неопределено Тогда
		ПараметрыОбработчика = Новый Структура;
		ПараметрыОбработчика.Вставить("Обработчик", ОбработчикЗавершения(Обработчик));
		ПараметрыОбработчика.Вставить("Результат", Результат);
		Обработчик = Новый ОписаниеОповещения("ВернутьРезультатПослеЗакрытияПростогоДиалога", ЭтотОбъект, ПараметрыОбработчика);
		ПоказатьЗначение(Обработчик, Значение);
	Иначе
		ПоказатьЗначение(, Значение);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры (см. выше).
Процедура ВернутьРезультатПослеЗакрытияПростогоДиалога(Структура) Экспорт
	
	Если ТипЗнч(Структура.Обработчик) = Тип("ОписаниеОповещения") Тогда
		ВыполнитьОбработкуОповещения(Структура.Обработчик, Структура.Результат);
	КонецЕсли;
	
КонецПроцедуры

// Возвращает результат прямого вызова, когда не было открыто диалогов.
Процедура ВернутьРезультат(Обработчик, Результат) Экспорт
	
	Обработчик = ПодготовитьОбработчикДляПрямогоВызова(Обработчик, Результат);
	Если ТипЗнч(Обработчик) = Тип("ОписаниеОповещения") Тогда
		ВыполнитьОбработкуОповещения(Обработчик, Результат);
	КонецЕсли;
	
КонецПроцедуры

// Записывает информацию, необходимую для подготовки обработчика асинхронного диалога.
Процедура ЗарегистрироватьОбработчикЗавершения(ПараметрыВыполнения, ОбработчикЗавершения) Экспорт
	
	АсинхронныйДиалог = Новый Структура;
	АсинхронныйДиалог.Вставить("Модуль",                 ОбработчикЗавершения.Модуль);
	АсинхронныйДиалог.Вставить("ИмяПроцедуры",           ОбработчикЗавершения.ИмяПроцедуры);
	АсинхронныйДиалог.Вставить("Открыт",                 Ложь);
	АсинхронныйДиалог.Вставить("РезультатКогдаНеОткрыт", Неопределено);
	ПараметрыВыполнения.Вставить("АсинхронныйДиалог", АсинхронныйДиалог);
	
КонецПроцедуры

// Подготовка обработчика асинхронного диалога.
Функция ОбработчикЗавершения(ОбработчикИлиСтруктура)
	
	Обработчик = Неопределено;
	Если ТипЗнч(ОбработчикИлиСтруктура) = Тип("Структура") Тогда
		УстановитьПризнакБлокирующейФормы(ОбработчикИлиСтруктура, Истина);
		АсинхронныйДиалог = Неопределено;
		Если ОбработчикИлиСтруктура.Свойство("АсинхронныйДиалог", АсинхронныйДиалог) Тогда
			Обработчик = Новый ОписаниеОповещения(АсинхронныйДиалог.ИмяПроцедуры, АсинхронныйДиалог.Модуль,	
				ОбработчикИлиСтруктура);
		КонецЕсли;
	Иначе
		Обработчик = ОбработчикИлиСтруктура;
	КонецЕсли;
	Возврат Обработчик;
	
КонецФункции

Процедура УстановитьПризнакБлокирующейФормы(ПараметрыВыполнения, Значение) Экспорт
	
	// Рекурсивная регистрация всех обработчиков вызывающего кода.
	Если ПараметрыВыполнения.Свойство("ОбработчикРезультата") Тогда
		ПараметрыВыполнения.ОбработчикРезультата = ОбработчикЗавершения(ПараметрыВыполнения.ОбработчикРезультата);
	КонецЕсли;
	АсинхронныйДиалог = Неопределено;
	Если ПараметрыВыполнения.Свойство("АсинхронныйДиалог", АсинхронныйДиалог) Тогда
		АсинхронныйДиалог.Открыт = Значение;
	КонецЕсли;
	
КонецПроцедуры

Функция БлокирующаяФормаОткрыта(ПараметрыВыполнения) Экспорт
	
	АсинхронныйДиалог = Неопределено;
	Если ПараметрыВыполнения.Свойство("АсинхронныйДиалог", АсинхронныйДиалог) Тогда
		Возврат АсинхронныйДиалог.Открыт;
	КонецЕсли;
	Возврат Ложь;
	
КонецФункции

// Подготовка обработчика прямого вызова без открытия диалога.
Функция ПодготовитьОбработчикДляПрямогоВызова(ОбработчикИлиСтруктура, Результат)
	
	Если ТипЗнч(ОбработчикИлиСтруктура) = Тип("Структура") Тогда
		Если ОбработчикИлиСтруктура.Свойство("АсинхронныйДиалог") Тогда
			ОбработчикИлиСтруктура.АсинхронныйДиалог.РезультатКогдаНеОткрыт = Результат;
		КонецЕсли;
		Возврат Неопределено; // Обработчик не был подготовлен для диалога => Вызывающий код не остановился.
	Иначе
		Возврат ОбработчикИлиСтруктура;
	КонецЕсли;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Выполняет пакет неинтерактивных действий с файлом.
// Если файл не существует, то действия не будут пропущены.
//
// Можно получить следующие свойства: Имя, ИмяБезРасширения, ПолноеИмя, Путь, Расширение, Существует,
//    ВремяИзменения, УниверсальноеВремяИзменения, ТолькоЧтение, Невидимость, Размер, ЭтоКаталог, ЭтоФайл.
//
// Можно установить следующие свойства: ВремяИзменения, УниверсальноеВремяИзменения, ТолькоЧтение, Невидимость.
// Можно выполнить действия с файлом: Удалить.
//
// Параметры:
//  Оповещение - ОписаниеОповещения - оповещение, которое выполняется после выполнения
//   действий с файлом. В качестве результата возвращается Структура со свойствами:
//     * ОписаниеОшибки - Строка - текст ошибки, если одно из действий выполнить не удалось.
//     * Результаты     - Массив - содержит результат по каждому действию в виде структуры:
//             * Файл       - Файл - инициализированный объект файл.
//                          - Неопределено - ошибка инициализации файла.
//             * Существует - Булево - Ложь, если файл не существует.
//
//  ДействияСФайлом - Массив - содержащий структуры с именем действия и параметрами действия:
//    * Действие - Строка    - ПолучитьСвойства, УстановитьСвойства, Удалить, СкопироватьИзИсточника,
//                             СоздатьКаталог, Получить, Поместить.
//    * Файл     - Строка    - полное имя файла на компьютере.
//               - Файл      - инициализированный объект Файл.
//    * Свойства - см. свойства которые можно получить или установить.
//    * Источник - Строка    - полное имя файла на компьютере из которого нужно создать копию.
//    * Адрес    - Строка    - адрес двоичных данных файла, например, адрес временного хранилища.
//    * ЗаголовокОшибки - Строка - текст к которому нужно добавить перевод строки и представление ошибки.
//
Процедура ОбработатьФайл(Оповещение, ДействияСФайлом, ИдентификаторФормы = Неопределено)
	
	Контекст = Новый Структура;
	Контекст.Вставить("Оповещение",         Оповещение);
	Контекст.Вставить("ДействияСФайлом",    ДействияСФайлом);
	Контекст.Вставить("ИдентификаторФормы", ИдентификаторФормы);
	
	Контекст.Вставить("РезультатДействий", Новый Структура);
	Контекст.РезультатДействий.Вставить("ОписаниеОшибки", "");
	Контекст.РезультатДействий.Вставить("Результаты", Новый Массив);
	
	Контекст.Вставить("Индекс", -1);
	ОбработатьФайлЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
//
// Параметры:
//   Контекст - Структура:
//     * РезультатДействий - Структура:
//       ** Результаты - Массив
//
Процедура ОбработатьФайлЦиклНачало(Контекст)
	
	Если Контекст.Индекс + 1 >= Контекст.ДействияСФайлом.Количество() Тогда
		ВыполнитьОбработкуОповещения(Контекст.Оповещение, Контекст.РезультатДействий);
		Возврат;
	КонецЕсли;
	
	Контекст.Индекс = Контекст.Индекс + 1;
	Контекст.Вставить("ОписаниеДействия", Контекст.ДействияСФайлом[Контекст.Индекс]);
	
	Контекст.Вставить("Результат",  Новый Структура);
	Контекст.Результат.Вставить("Файл", Неопределено);
	Контекст.Результат.Вставить("Существует", Ложь);
	
	Контекст.РезультатДействий.Результаты.Добавить(Контекст.Результат);
	
	Контекст.Вставить("СвойстваДляПолучения", Новый Структура);
	Контекст.Вставить("СвойстваДляУстановки", Новый Структура);
	
	Действие = Контекст.ОписаниеДействия.Действие;
	Файл = Контекст.ОписаниеДействия.Файл;
	ПолноеИмяФайла = ?(ТипЗнч(Файл) = Тип("Файл"), Файл.ПолноеИмя, Файл);
	
	Если Действие = "Удалить" Тогда
		НачатьУдалениеФайлов(Новый ОписаниеОповещения(
			"ОбработатьФайлПослеУдаленияФайлов", ЭтотОбъект, Контекст,
			"ОбработатьФайлПослеОшибки", ЭтотОбъект), ПолноеИмяФайла);
		Возврат;
	
	ИначеЕсли Действие = "СкопироватьИзИсточника" Тогда
		НачатьКопированиеФайла(Новый ОписаниеОповещения(
			"ОбработатьФайлПослеКопированияФайла", ЭтотОбъект, Контекст,
			"ОбработатьФайлПослеОшибки", ЭтотОбъект), Контекст.ОписаниеДействия.Источник, ПолноеИмяФайла);
		Возврат;
	
	ИначеЕсли Действие = "СоздатьКаталог" Тогда
		НачатьСозданиеКаталога(Новый ОписаниеОповещения(
			"ОбработатьФайлПослеСозданияКаталога", ЭтотОбъект, Контекст,
			"ОбработатьФайлПослеОшибки", ЭтотОбъект), ПолноеИмяФайла);
		Возврат;
	
	ИначеЕсли Действие = "Получить" Тогда
		ОписаниеФайла = Новый ОписаниеПередаваемогоФайла(ПолноеИмяФайла, Контекст.ОписаниеДействия.Адрес);
		ПолучаемыеФайлы = Новый Массив;
		ПолучаемыеФайлы.Добавить(ОписаниеФайла);
		НачатьПолучениеФайлов(Новый ОписаниеОповещения(
				"ОбработатьФайлПослеПолученияФайлов", ЭтотОбъект, Контекст,
				"ОбработатьФайлПослеОшибки", ЭтотОбъект),
			ПолучаемыеФайлы, , Ложь);
		Возврат;
	
	ИначеЕсли Действие = "Поместить" Тогда
		ОписаниеФайла = Новый ОписаниеПередаваемогоФайла(ПолноеИмяФайла);
		ПомещаемыеФайлы = Новый Массив;
		ПомещаемыеФайлы.Добавить(ОписаниеФайла);
		НачатьПомещениеФайлов(Новый ОписаниеОповещения(
				"ОбработатьФайлПослеПомещенияФайлов", ЭтотОбъект, Контекст,
				"ОбработатьФайлПослеОшибки", ЭтотОбъект),
			ПомещаемыеФайлы, , Ложь, Контекст.ИдентификаторФормы);
		Возврат;
	
	ИначеЕсли Действие = "ПолучитьСвойства" Тогда
		Контекст.Вставить("СвойстваДляПолучения", Контекст.ОписаниеДействия.Свойства);
		
	ИначеЕсли Действие = "УстановитьСвойства" Тогда
		Контекст.Вставить("СвойстваДляУстановки", Контекст.ОписаниеДействия.Свойства);
	КонецЕсли;
	
	Контекст.Вставить("Файл", ?(ТипЗнч(Файл) = Тип("Файл"), Файл, Новый Файл(Файл)));
	Контекст.Результат.Вставить("Файл", Контекст.Файл);
	ЗаполнитьЗначенияСвойств(Контекст.СвойстваДляПолучения, Контекст.Файл);
	Контекст.Файл.НачатьПроверкуСуществования(Новый ОписаниеОповещения(
		"ОбработатьФайлПослеПроверкиСуществования", ЭтотОбъект, Контекст,
		"ОбработатьФайлПослеОшибки", ЭтотОбъект));
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
Процедура ОбработатьФайлПослеОшибки(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
	
	СтандартнаяОбработка = Ложь;
	
	Если ТипЗнч(ИнформацияОбОшибке) = Тип("ИнформацияОбОшибке") Тогда
		Контекст.РезультатДействий.ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
	Иначе
		Контекст.РезультатДействий.ОписаниеОшибки = ИнформацияОбОшибке;
	КонецЕсли;
	
	Если Контекст.ОписаниеДействия.Свойство("ЗаголовокОшибки") Тогда
		Контекст.РезультатДействий.ОписаниеОшибки = Контекст.ОписаниеДействия.ЗаголовокОшибки
			+ Символы.ПС + Контекст.РезультатДействий.ОписаниеОшибки;
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(Контекст.Оповещение, Контекст.РезультатДействий);
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
Процедура ОбработатьФайлПослеУдаленияФайлов(Контекст) Экспорт
	
	ОбработатьФайлЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
Процедура ОбработатьФайлПослеКопированияФайла(СкопированныйФайл, Контекст) Экспорт
	
	ОбработатьФайлЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
Процедура ОбработатьФайлПослеСозданияКаталога(ИмяКаталога, Контекст) Экспорт
	
	ОбработатьФайлЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
Процедура ОбработатьФайлПослеПолученияФайлов(ПолученныеФайлы, Контекст) Экспорт
	
	Если ТипЗнч(ПолученныеФайлы) <> Тип("Массив") Или ПолученныеФайлы.Количество() = 0 Тогда
		ОбработатьФайлПослеОшибки(НСтр("ru = 'Получение файла было отменено.'"), Неопределено, Контекст);
		Возврат;
	КонецЕсли;
	
	ОбработатьФайлЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
Процедура ОбработатьФайлПослеПомещенияФайлов(ПомещенныеФайлы, Контекст) Экспорт
	
	Если ТипЗнч(ПомещенныеФайлы) <> Тип("Массив") Или ПомещенныеФайлы.Количество() = 0 Тогда
		ОбработатьФайлПослеОшибки(НСтр("ru = 'Помещение файла было отменено.'"), Неопределено, Контекст);
		Возврат;
	КонецЕсли;
	
	Контекст.ОписаниеДействия.Вставить("Адрес", ПомещенныеФайлы[0].Хранение);
	
	ОбработатьФайлЦиклНачало(Контекст);
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
//
// Параметры:
//  Существует - Булево
//  Контекст- Структура:
//   * Результат - Структура
//
Процедура ОбработатьФайлПослеПроверкиСуществования(Существует, Контекст) Экспорт
	
	Контекст.Результат.Вставить("Существует", Существует);
	
	Если Не Контекст.Результат.Существует Тогда
		ОбработатьФайлЦиклНачало(Контекст);
		Возврат;
	КонецЕсли;
	
	Если Контекст.СвойстваДляПолучения.Количество() = 0 Тогда
		ОбработатьФайлПослеПроверкиЭтоФайл(Null, Контекст);
		
	ИначеЕсли Контекст.СвойстваДляПолучения.Свойство("ВремяИзменения") Тогда
		Контекст.Файл.НачатьПолучениеВремениИзменения(Новый ОписаниеОповещения(
			"ОбработатьФайлПослеПолученияВремениИзменения", ЭтотОбъект, Контекст,
			"ОбработатьФайлПослеОшибки", ЭтотОбъект));
	Иначе
		ОбработатьФайлПослеПолученияВремениИзменения(Null, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
Процедура ОбработатьФайлПослеПолученияВремениИзменения(ВремяИзменения, Контекст) Экспорт
	
	Если ВремяИзменения <> Null Тогда
		Контекст.СвойстваДляПолучения.ВремяИзменения = ВремяИзменения;
	КонецЕсли;
	
	Если Контекст.СвойстваДляПолучения.Свойство("УниверсальноеВремяИзменения") Тогда
		Контекст.Файл.НачатьПолучениеУниверсальногоВремениИзменения(Новый ОписаниеОповещения(
			"ОбработатьФайлПослеПолученияУниверсальногоВремениИзменения", ЭтотОбъект, Контекст,
			"ОбработатьФайлПослеОшибки", ЭтотОбъект));
	Иначе
		ОбработатьФайлПослеПолученияУниверсальногоВремениИзменения(Null, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
Процедура ОбработатьФайлПослеПолученияУниверсальногоВремениИзменения(УниверсальноеВремяИзменения, Контекст) Экспорт
	
	Если УниверсальноеВремяИзменения <> Null Тогда
		Контекст.СвойстваДляПолучения.УниверсальноеВремяИзменения = УниверсальноеВремяИзменения;
	КонецЕсли;
	
	Если Контекст.СвойстваДляПолучения.Свойство("ТолькоЧтение") Тогда
		Контекст.Файл.НачатьПолучениеТолькоЧтения(Новый ОписаниеОповещения(
			"ОбработатьФайлПослеПолученияТолькоЧтения", ЭтотОбъект, Контекст,
			"ОбработатьФайлПослеОшибки", ЭтотОбъект));
	Иначе
		ОбработатьФайлПослеПолученияТолькоЧтения(Null, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
Процедура ОбработатьФайлПослеПолученияТолькоЧтения(ТолькоЧтение, Контекст) Экспорт
	
	Если ТолькоЧтение <> Null Тогда
		Контекст.СвойстваДляПолучения.ТолькоЧтение = ТолькоЧтение;
	КонецЕсли;
	
	Если Контекст.СвойстваДляПолучения.Свойство("Невидимость") Тогда
		Контекст.Файл.НачатьПолучениеНевидимости(Новый ОписаниеОповещения(
			"ОбработатьФайлПослеПолученияНевидимости", ЭтотОбъект, Контекст,
			"ОбработатьФайлПослеОшибки", ЭтотОбъект));
	Иначе
		ОбработатьФайлПослеПолученияНевидимости(Null, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
//
// Параметры:
//  Невидимость - Булево
//  Контекст - Структура:
//     * Файл - Файл
//     * СвойстваДляПолучения - Структура:
//       ** Размер - Число
//       ** ЭтоКаталог - Булево
//
Процедура ОбработатьФайлПослеПолученияНевидимости(Невидимость, Контекст) Экспорт
	
	Если Невидимость <> Null Тогда
		Контекст.СвойстваДляПолучения.Невидимость = Невидимость;
	КонецЕсли;
	
	Если Контекст.СвойстваДляПолучения.Свойство("Размер") Тогда
		Контекст.Файл.НачатьПолучениеРазмера(Новый ОписаниеОповещения(
			"ОбработатьФайлПослеПолученияРазмера", ЭтотОбъект, Контекст,
			"ОбработатьФайлПослеОшибки", ЭтотОбъект));
	Иначе
		ОбработатьФайлПослеПолученияРазмера(Null, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
Процедура ОбработатьФайлПослеПолученияРазмера(Размер, Контекст) Экспорт
	
	Если Размер <> Null Тогда
		Контекст.СвойстваДляПолучения.Размер = Размер;
	КонецЕсли;
	
	Если Контекст.СвойстваДляПолучения.Свойство("ЭтоКаталог") Тогда
		Контекст.Файл.НачатьПроверкуЭтоКаталог(Новый ОписаниеОповещения(
			"ОбработатьФайлПослеПроверкиЭтоКаталог", ЭтотОбъект, Контекст,
			"ОбработатьФайлПослеОшибки", ЭтотОбъект));
	Иначе
		ОбработатьФайлПослеПроверкиЭтоКаталог(Null, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
Процедура ОбработатьФайлПослеПроверкиЭтоКаталог(ЭтоКаталог, Контекст) Экспорт
	
	Если ЭтоКаталог <> Null Тогда
		Контекст.СвойстваДляПолучения.ЭтоКаталог = ЭтоКаталог;
	КонецЕсли;
	
	Если Контекст.СвойстваДляПолучения.Свойство("ЭтоФайл") Тогда
		Контекст.Файл.НачатьПроверкуЭтоФайл(Новый ОписаниеОповещения(
			"ОбработатьФайлПослеПроверкиЭтоФайл", ЭтотОбъект, Контекст,
			"ОбработатьФайлПослеОшибки", ЭтотОбъект));
	Иначе
		ОбработатьФайлПослеПроверкиЭтоФайл(Null, Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
Процедура ОбработатьФайлПослеПроверкиЭтоФайл(ЭтоФайл, Контекст) Экспорт
	
	Если ЭтоФайл <> Null Тогда
		Контекст.СвойстваДляПолучения.ЭтоФайл = ЭтоФайл;
	КонецЕсли;
	
	Если Контекст.СвойстваДляУстановки.Количество() = 0 Тогда
		ОбработатьФайлПослеУстановкиНевидимости(Контекст);
		
	ИначеЕсли Контекст.СвойстваДляУстановки.Свойство("ВремяИзменения") Тогда
		Контекст.Файл.НачатьУстановкуВремениИзменения(Новый ОписаниеОповещения(
			"ОбработатьФайлПослеУстановкиВремениИзменения", ЭтотОбъект, Контекст,
			"ОбработатьФайлПослеОшибки", ЭтотОбъект), Контекст.СвойстваДляУстановки.ВремяИзменения);
	Иначе
		ОбработатьФайлПослеУстановкиВремениИзменения(Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
Процедура ОбработатьФайлПослеУстановкиВремениИзменения(Контекст) Экспорт
	
	Если Контекст.СвойстваДляУстановки.Свойство("УниверсальноеВремяИзменения") Тогда
		Контекст.Файл.НачатьУстановкуУниверсальногоВремениИзменения(Новый ОписаниеОповещения(
			"ОбработатьФайлПослеУстановкиУниверсальногоВремениИзменения", ЭтотОбъект, Контекст,
			"ОбработатьФайлПослеОшибки", ЭтотОбъект), Контекст.СвойстваДляУстановки.УниверсальноеВремяИзменения);
	Иначе
		ОбработатьФайлПослеУстановкиУниверсальногоВремениИзменения(Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
Процедура ОбработатьФайлПослеУстановкиУниверсальногоВремениИзменения(Контекст) Экспорт
	
	Если Контекст.СвойстваДляУстановки.Свойство("ТолькоЧтение") Тогда
		Контекст.Файл.НачатьУстановкуТолькоЧтения(Новый ОписаниеОповещения(
			"ОбработатьФайлПослеУстановкиТолькоЧтения", ЭтотОбъект, Контекст,
			"ОбработатьФайлПослеОшибки", ЭтотОбъект), Контекст.СвойстваДляУстановки.ТолькоЧтение);
	Иначе
		ОбработатьФайлПослеУстановкиТолькоЧтения(Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
Процедура ОбработатьФайлПослеУстановкиТолькоЧтения(Контекст) Экспорт
	
	Если Контекст.СвойстваДляУстановки.Свойство("Невидимость") Тогда
		Контекст.Файл.НачатьУстановкуНевидимости(Новый ОписаниеОповещения(
			"ОбработатьФайлПослеУстановкиНевидимости", ЭтотОбъект, Контекст,
			"ОбработатьФайлПослеОшибки", ЭтотОбъект), Контекст.СвойстваДляУстановки.Невидимость);
	Иначе
		ОбработатьФайлПослеУстановкиНевидимости(Контекст);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ОбработатьФайл.
Процедура ОбработатьФайлПослеУстановкиНевидимости(Контекст) Экспорт
	
	ОбработатьФайлЦиклНачало(Контекст);
	
КонецПроцедуры

// Загружает файл с клиента во временное хранилище на сервере. Не работает без расширения для работы с 1С:Предприятием.
Функция ПоместитьФайлСДискаВоВременноеХранилище(ПолноеИмяФайла, АдресФайла = "", УникальныйИдентификатор = Неопределено)
	Если Не РасширениеРаботыСФайламиПодключено() Тогда
		Возврат Неопределено;
	КонецЕсли;
	ЧтоЗагрузить = Новый Массив;
	ЧтоЗагрузить.Добавить(Новый ОписаниеПередаваемогоФайла(ПолноеИмяФайла, АдресФайла));
	РезультатЗагрузки = Новый Массив;
	ФайлЗагружен = ПоместитьФайлы(ЧтоЗагрузить, РезультатЗагрузки, , Ложь, УникальныйИдентификатор);
	Если Не ФайлЗагружен Или РезультатЗагрузки.Количество() = 0 Тогда
		Возврат Неопределено;
	КонецЕсли;
	Возврат РезультатЗагрузки[0].Хранение;
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Процедуры и функция для работы со сканером.

Процедура ПроинициализироватьКомпоненту(ОповещениеВозврата, ПредложитьУстановить = Ложь) Экспорт
	
	Если Не ДоступноСканирование() Тогда 
		РезультатПодключенияКомпоненты = ОбщегоНазначенияСлужебныйКлиент.РезультатПодключенияКомпоненты();
		РезультатПодключенияКомпоненты.Подключено = Ложь;
		РезультатПодключенияКомпоненты.ОписаниеОшибки = НСтр("ru = 'Сканирование возможно в программах для операционных систем Microsoft Windows x86 и х64'");
		ВыполнитьОбработкуОповещения(ОповещениеВозврата, РезультатПодключенияКомпоненты);
		Возврат;
	КонецЕсли;
	
	ПараметрыПодключения = ОбщегоНазначенияКлиент.ПараметрыПодключенияКомпоненты();
	ПараметрыПодключения.ТекстПояснения = НСтр("ru = 'Для продолжения требуется подключить внешнюю компоненту сканирования.'");
	ПараметрыПодключения.ПредложитьУстановить = ПредложитьУстановить;
	
	ОписаниеКомпоненты = РаботаСФайламиСлужебныйКлиентСервер.ОписаниеКомпоненты();
	ОбщегоНазначенияКлиент.ПодключитьКомпонентуИзМакета(ОповещениеВозврата, ОписаниеКомпоненты.ИмяОбъекта, ОписаниеКомпоненты.ПолноеИмяМакета, ПараметрыПодключения);
	
КонецПроцедуры

Функция ДоступноСканирование(ЭтоПроверкаНастроек = Ложь) Экспорт
	
	Если ЭтоПроверкаНастроек Тогда
#Если МобильныйКлиент Тогда
		Возврат СредстваМультимедиа.ПоддерживаетсяФотоснимок();
#ИначеЕсли ВебКлиент Тогда
		Возврат Ложь;
#Иначе
		Возврат ОбщегоНазначенияКлиент.ЭтоWindowsКлиент();
#КонецЕсли
	Иначе
#Если МобильныйКлиент ИЛИ ВебКлиент Тогда
		Возврат Ложь;
#Иначе
		Возврат ОбщегоНазначенияКлиент.ЭтоWindowsКлиент();
#КонецЕсли
	КонецЕсли;
	
КонецФункции

// Возвращает устройства сканирования (массив строк).
Функция ПолучитьУстройства(Форма, ПодключаемыйМодуль) Экспорт
	
	Устройства = ПодключенныеУстройства(Форма, ПодключаемыйМодуль);
	
	Возврат Устройства;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Вспомогательные процедуры для поддержки асинхронной модели.
//
Функция КлиентПоддерживаетСинхронныеВызовы()
	
#Если ВебКлиент Тогда
	// В Chrome и Firefox синхронные методы не поддерживаются.
	СистемнаяИнформация = Новый СистемнаяИнформация;
	ИнформацияПрограммыМассив = СтрРазделить(СистемнаяИнформация.ИнформацияПрограммыПросмотра, " ", Ложь);
	
	Для Каждого ИнформацияПрограммы Из ИнформацияПрограммыМассив Цикл
		Если СтрНайти(ИнформацияПрограммы, "Chrome") > 0 ИЛИ СтрНайти(ИнформацияПрограммы, "Firefox") > 0 Тогда
			Возврат Ложь;
		КонецЕсли;
	КонецЦикла;
#КонецЕсли
	
	Возврат Истина;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Обработка событий общих форм работы с файлами.

// Выбрать режим открытия файла и начать редактирование.
// Варианты "Редактировать", "Отмена".
//
// Параметры:
//   ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//
Процедура ВыбратьРежимИРедактироватьФайл(ОбработчикРезультата, ДанныеФайла, ДоступностьКомандыРедактировать) Экспорт
	
	ПерсональныеНастройки = ПерсональныеНастройкиРаботыСФайлами();
	РезультатОткрыть = ?(ДанныеФайла.ФайлРедактируетТекущийПользователь И ДоступностьКомандыРедактировать,
		"Редактировать", ПерсональныеНастройки.ВариантОткрытияФайла);
	
	СпособОткрытия = ПерсональныеНастройки.ТекстовыеФайлыСпособОткрытия;
	Если СпособОткрытия = ПредопределенноеЗначение("Перечисление.СпособыОткрытияФайлаНаПросмотр.ВоВстроенномРедакторе") Тогда
		
		РасширениеВСписке = РаботаСФайламиСлужебныйКлиентСервер.РасширениеФайлаВСписке(
			ПерсональныеНастройки.ТекстовыеФайлыРасширение,
			ДанныеФайла.Расширение);
		
		Если РасширениеВСписке Тогда
			ВернутьРезультат(ОбработчикРезультата, РезультатОткрыть);
			Возврат;
		КонецЕсли;
		
	КонецЕсли;
	
	СпособОткрытия = ПерсональныеНастройки.ГрафическиеСхемыСпособОткрытия;
	Если СпособОткрытия = ПредопределенноеЗначение("Перечисление.СпособыОткрытияФайлаНаПросмотр.ВоВстроенномРедакторе") Тогда
		
		РасширениеВСписке = РаботаСФайламиСлужебныйКлиентСервер.РасширениеФайлаВСписке(
			ПерсональныеНастройки.ГрафическиеСхемыРасширение,
			ДанныеФайла.Расширение);
		
		Если РасширениеВСписке Тогда
			ВернутьРезультат(ОбработчикРезультата, РезультатОткрыть);
			Возврат;
		КонецЕсли;
		
	КонецЕсли;
	
	// Если уже занят для редактирования, то не спрашивать - сразу открывать.
	Если Не ЗначениеЗаполнено(ДанныеФайла.Редактирует)
		И ПерсональныеНастройки.СпрашиватьРежимРедактированияПриОткрытииФайла = Истина
		И ДоступностьКомандыРедактировать Тогда
		
		ПараметрыВыполнения = Новый Структура;
		ПараметрыВыполнения.Вставить("ОбработчикРезультата", ОбработчикРезультата);
		Обработчик = Новый ОписаниеОповещения("ВыбратьРежимИРедактироватьФайлЗавершение", ЭтотОбъект, ПараметрыВыполнения);
		
		ОткрытьФорму("Обработка.РаботаСФайлами.Форма.ФормаВыбораРежимаОткрытия", , , , , , Обработчик, РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);
		Возврат;
	КонецЕсли;
	
	ВернутьРезультат(ОбработчикРезультата, РезультатОткрыть);
	
КонецПроцедуры

Процедура ВыбратьРежимИРедактироватьФайлЗавершение(Результат, ПараметрыВыполнения) Экспорт
	
	РезультатОткрыть = "Открыть";
	РезультатРедактировать = "Редактировать";
	РезультатОтмена = "Отмена";
	
	Если ТипЗнч(Результат) <> Тип("Структура") Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, РезультатОтмена);
		Возврат;
	КонецЕсли;
	
	Если Результат.КакОткрывать = 1 Тогда
		ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, РезультатРедактировать);
		Возврат;
	КонецЕсли;
	
	ВернутьРезультат(ПараметрыВыполнения.ОбработчикРезультата, РезультатОткрыть);
	
КонецПроцедуры

// Доступны файловые команды, есть хотя бы одна строка в списке и выделена не группировка.
// 
// Параметры:
//  Элементы - ЭлементыФормы:
//    * Список - ТаблицаФормы
// 
// Возвращаемое значение:
//  Булево
//
Функция ФайловыеКомандыДоступны(Элементы) Экспорт
	
	ФайлСсылка = Элементы.Список.ТекущаяСтрока;
	
	Если ФайлСсылка = Неопределено Тогда 
		Возврат Ложь;
	КонецЕсли;
	
	Если ТипЗнч(Элементы.Список.ТекущаяСтрока) = Тип("СтрокаГруппировкиДинамическогоСписка") Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

///////////////////////////////////////////////////////////////////////////////////
// Печать табличного или офисного документа со штампом электронной подписи.

Процедура ПечатьФайлаСоШтампом(Документ, НаименованиеФайла) Экспорт
	
	НаименованиеДокумента = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '%1 (со штампом)'"), 
				НаименованиеФайла);
	
	Если ТипЗнч(Документ) = Тип("ТабличныйДокумент") Тогда
		Если ОбщегоНазначенияКлиент.ПодсистемаСуществует("СтандартныеПодсистемы.Печать") Тогда
			МодульУправлениеПечатьюКлиент = ОбщегоНазначенияКлиент.ОбщийМодуль("УправлениеПечатьюКлиент");
			ИдентификаторПечатнойФормы = "ПрисоединенныйФайл";
			Документ.Защита = Ложь;
			
			КоллекцияПечатныхФорм = МодульУправлениеПечатьюКлиент.НоваяКоллекцияПечатныхФорм(ИдентификаторПечатнойФормы);
			ПечатнаяФорма = МодульУправлениеПечатьюКлиент.ОписаниеПечатнойФормы(КоллекцияПечатныхФорм, ИдентификаторПечатнойФормы);
			ПечатнаяФорма.СинонимМакета = НаименованиеДокумента;
			ПечатнаяФорма.ТабличныйДокумент = Документ;
			
			МодульУправлениеПечатьюКлиент.ПечатьДокументов(КоллекцияПечатныхФорм);
		Иначе
			Документ.Напечатать(РежимИспользованияДиалогаПечати.Использовать);
		КонецЕсли;
	Иначе
		ФайловаяСистемаКлиент.ОткрытьФайл(Документ, , НаименованиеДокумента+".docx");
	КонецЕсли;
	
КонецПроцедуры

// Обратная совместимость. Открытие файла без владельца по адресу на временное хранилище.

// Продолжение процедуры ОткрытьФайл.
Процедура ОткрытьФайлРасширениеПредложено(РасширениеРаботыСФайламиПодключено, ДополнительныеПараметры) Экспорт
	
	ДанныеФайла = ДополнительныеПараметры.ДанныеФайла;
	ДляРедактирования = ДополнительныеПараметры.ДляРедактирования;
	
	Если РасширениеРаботыСФайламиПодключено Тогда
		
		РабочийКаталогПользователя = РабочийКаталогПользователя();
		ПолноеИмяФайлаНаКлиенте = РабочийКаталогПользователя + ДанныеФайла.ОтносительныйПуть + ДанныеФайла.ИмяФайла;
		ФайлНаДиске = Новый Файл(ПолноеИмяФайлаНаКлиенте);
		
		ДополнительныеПараметры.Вставить("ДляРедактирования", ДляРедактирования);
		ДополнительныеПараметры.Вставить("РабочийКаталогПользователя", РабочийКаталогПользователя);
		ДополнительныеПараметры.Вставить("ФайлНаДиске", ФайлНаДиске);
		ДополнительныеПараметры.Вставить("ПолноеИмяФайлаНаКлиенте", ПолноеИмяФайлаНаКлиенте);
		
		Если ЗначениеЗаполнено(ДанныеФайла.Редактирует) И ДляРедактирования И ФайлНаДиске.Существует() Тогда
			ФайлНаДиске.УстановитьТолькоЧтение(Ложь);
			ПолучитьФайл = Ложь;
		ИначеЕсли ФайлНаДиске.Существует() Тогда
			ОписаниеОповещения = Новый ОписаниеОповещения("ОткрытьФайлДиалогПоказан", ЭтотОбъект, ДополнительныеПараметры);
			ПоказатьДиалогНужноПолучитьФайлССервера(ОписаниеОповещения, ПолноеИмяФайлаНаКлиенте, ДанныеФайла, ДляРедактирования);
			Возврат;
		Иначе
			ПолучитьФайл = Истина;
		КонецЕсли;
		
		ОткрытьФайлДиалогПоказан(ПолучитьФайл, ДополнительныеПараметры);
	Иначе
		ОписаниеОповещения = Новый ОписаниеОповещения("ОткрытьФайлНапоминаниеПоказано", ЭтотОбъект, ДополнительныеПараметры);
		ВывестиНапоминаниеПриРедактировании(ОписаниеОповещения);
	КонецЕсли;
	
КонецПроцедуры

// Продолжение процедуры ОткрытьФайл.
Процедура ОткрытьФайлНапоминаниеПоказано(РезультатНапоминания, ДополнительныеПараметры) Экспорт
	
	Если РезультатНапоминания = КодВозвратаДиалога.Отмена Или РезультатНапоминания = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ДанныеФайла = ДополнительныеПараметры.ДанныеФайла;
	ПолучитьФайл(ДанныеФайла.СсылкаНаДвоичныеДанныеФайла, ДанныеФайла.ИмяФайла, Истина);
	
КонецПроцедуры

// Продолжение процедуры ОткрытьФайл.
Процедура ОткрытьФайлДиалогПоказан(ПолучитьФайл, ДополнительныеПараметры) Экспорт
	
	Если ПолучитьФайл = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ДанныеФайла = ДополнительныеПараметры.ДанныеФайла;
	ДляРедактирования = ДополнительныеПараметры.ДляРедактирования;
	РабочийКаталогПользователя = ДополнительныеПараметры.РабочийКаталогПользователя;
	ФайлНаДиске = ДополнительныеПараметры.ФайлНаДиске;
	ПолноеИмяФайлаНаКлиенте = ДополнительныеПараметры.ПолноеИмяФайлаНаКлиенте;
	
	ФайлМожноОткрывать = Истина;
	Если ПолучитьФайл Тогда
		ПолноеИмяФайлаНаКлиенте = "";
		ФайлМожноОткрывать = ПолучитьФайлВРабочийКаталог(
			ДанныеФайла.СсылкаНаДвоичныеДанныеФайла,
			ДанныеФайла.ОтносительныйПуть,
			ДанныеФайла.ДатаМодификацииУниверсальная,
			ДанныеФайла.ИмяФайла,
			РабочийКаталогПользователя,
			ПолноеИмяФайлаНаКлиенте);
	КонецЕсли;
		
	Если ФайлМожноОткрывать Тогда
		
		Если ДляРедактирования Тогда
			ФайлНаДиске.УстановитьТолькоЧтение(Ложь);
		Иначе
			ФайлНаДиске.УстановитьТолькоЧтение(Истина);
		КонецЕсли;
		
		УникальныйИдентификатор = ?(ДополнительныеПараметры.Свойство("УникальныйИдентификатор"),
			ДополнительныеПараметры.УникальныйИдентификатор, Неопределено);
			
		ОткрытьФайлПриложением(ДанныеФайла, ПолноеИмяФайлаНаКлиенте, УникальныйИдентификатор);
		
	КонецЕсли;
		
КонецПроцедуры

Функция ПолучитьФайлВРабочийКаталог(Знач АдресДвоичныхДанныхФайла,
                                    Знач ОтносительныйПуть,
                                    Знач ДатаМодификацииУниверсальная,
                                    Знач ИмяФайла,
                                    Знач РабочийКаталогПользователя,
                                    ПолноеИмяФайлаНаКлиенте)
	
	Если РабочийКаталогПользователя = Неопределено
	 ИЛИ ПустаяСтрока(РабочийКаталогПользователя) Тогда
		
		Возврат Ложь;
	КонецЕсли;
	
	КаталогСохранения = РабочийКаталогПользователя + ОтносительныйПуть;
	
	Попытка
		СоздатьКаталог(КаталогСохранения);
	Исключение
		СообщениеОбОшибке = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
		СообщениеОбОшибке = НСтр("ru = 'Ошибка создания каталога на компьютере:'") + " " + СообщениеОбОшибке;
		ОбщегоНазначенияКлиент.СообщитьПользователю(СообщениеОбОшибке);
		Возврат Ложь;
	КонецПопытки;
	
	Файл = Новый Файл(КаталогСохранения + ИмяФайла);
	Если Файл.Существует() Тогда
		Попытка
			Файл.УстановитьТолькоЧтение(Ложь);
			УдалитьФайлы(КаталогСохранения + ИмяФайла);
		Исключение
			ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
				"Предупреждение", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()),, Истина);
		КонецПопытки;	
	КонецЕсли;
	
	ПолучаемыйФайл = Новый ОписаниеПередаваемогоФайла(КаталогСохранения + ИмяФайла, АдресДвоичныхДанныхФайла);
	ПолучаемыеФайлы = Новый Массив;
	ПолучаемыеФайлы.Добавить(ПолучаемыйФайл);
	
	ПолученныеФайлы = Новый Массив;
	
	Если ПолучитьФайлы(ПолучаемыеФайлы, ПолученныеФайлы, , Ложь) Тогда
		ПолноеИмяФайлаНаКлиенте = ПолученныеФайлы[0].ПолноеИмя;
		УстановитьУниверсальноеВремяИзменения(ПолноеИмяФайлаНаКлиенте, ДатаМодификацииУниверсальная);
		Возврат Истина;
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

// Параметры:
//   ДанныеФайла - см. РаботаСФайламиСлужебныйВызовСервера.ДанныеФайла
//
Процедура ПоказатьДиалогНужноПолучитьФайлССервера(ОбработчикРезультата, Знач ИмяФайлаСПутем, Знач ДанныеФайла, Знач ДляРедактирования)
	
	СтандартныеДанныеФайла = Новый Структура;
	СтандартныеДанныеФайла.Вставить("ДатаМодификацииУниверсальная", ДанныеФайла.ДатаМодификацииУниверсальная);
	СтандартныеДанныеФайла.Вставить("Размер",                       ДанныеФайла.Размер);
	СтандартныеДанныеФайла.Вставить("ВРабочемКаталогеНаЧтение",     НЕ ДляРедактирования);
	СтандартныеДанныеФайла.Вставить("Редактирует",                  ДанныеФайла.Редактирует);
	
	// Выяснено, что Файл в рабочем каталоге есть.
	// Проверка даты изменения и принятие решения, что делать дальше.
	
	Параметры = Новый Структура;
	Параметры.Вставить("ОбработчикРезультата", ОбработчикРезультата);
	Параметры.Вставить("ИмяФайлаСПутем", ИмяФайлаСПутем);
	ОписаниеОповещения = Новый ОписаниеОповещения("ПоказатьДиалогНужноПолучитьФайлССервераДействиеОпределено", ЭтотОбъект, Параметры);
	ДействиеПриОткрытииФайлаВРабочемКаталоге(ОписаниеОповещения, ИмяФайлаСПутем, СтандартныеДанныеФайла);
	
КонецПроцедуры

// Продолжение процедуры ПоказатьДиалогНужноПолучитьФайлССервера.
Процедура ПоказатьДиалогНужноПолучитьФайлССервераДействиеОпределено(Действие, ДополнительныеПараметры) Экспорт
	ИмяФайлаСПутем = ДополнительныеПараметры.ИмяФайлаСПутем;
	
	Если Действие = "ВзятьИзХранилищаИОткрыть" Тогда
		Файл = Новый Файл(ИмяФайлаСПутем);
		Попытка
			Файл.УстановитьТолькоЧтение(Ложь);
			УдалитьФайлы(ИмяФайлаСПутем);
		Исключение
			ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
				"Предупреждение", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()),, Истина);
			Результат = Неопределено;	
		КонецПопытки;	
		Результат = Истина;
	ИначеЕсли Действие = "ОткрытьСуществующий" Тогда
		Результат = Ложь;
	Иначе // Действие = "Отмена".
		Результат = Неопределено;
	КонецЕсли;
	
	ВыполнитьОбработкуОповещения(ДополнительныеПараметры.ОбработчикРезультата, Результат);
	
КонецПроцедуры

Функция ГотовностьКСканированию(Форма, ПодключаемыйМодуль) Экспорт 
	ЕстьУстройства = ЕстьУстройства(Форма, ПодключаемыйМодуль);
	
	Если ЕстьУстройства Тогда
		Попытка
			ПодключенныеУстройства(Форма, ПодключаемыйМодуль);
			Возврат Истина;
		Исключение
			Возврат Ложь;
		КонецПопытки;
	КонецЕсли;
	Возврат Ложь;
КонецФункции

Функция ПодключенныеУстройства(Форма, ПодключаемыйМодуль)
	ЗаписатьЖурналСканирования("ПолучитьУстройства.Старт");
	Попытка
		Устройства = ПодключаемыйМодуль.ПолучитьУстройства();
		ПодключенныеУстройства = СтрРазделить(Устройства, Символы.ПС, Ложь);
		ЗаписатьЖурналСканирования("ПолучитьУстройства.Результат", 
			СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("ПолучитьУстройства() = %1", 
			СтрСоединить(ПодключенныеУстройства, "|")));
	Исключение   
		ПодключенныеУстройства = Новый Массив;
		ПредставлениеОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ЗаписатьЖурналСканирования("ПолучитьУстройства", ПредставлениеОшибки, Истина);
		ПоказатьОшибкуСканирования(ПодключаемыйМодуль, Форма, НСтр("ru='Не удалось получить список устройств'"), ПредставлениеОшибки);
	КонецПопытки;
	Возврат ПодключенныеУстройства;
КонецФункции

// Возвращает настройку сканера по имени.
//
// Параметры:
//   ПодключаемыйМодуль - компонента сканирования
//   ИмяУстройства - Строка - имя сканера.
//   ИмяНастройки  - Строка - имя настройки,
//       например "XRESOLUTION", или "PIXELTYPE", или "ROTATION", или "SUPPORTEDSIZES".
//
// Возвращаемое значение:
//   Число - значение настройки сканера.
//
Функция НастройкаСканера(Форма, ПодключаемыйМодуль, ИмяУстройства, ИмяНастройки) Экспорт
	
	Если Не ДоступноСканирование(Истина) Тогда
		Возврат -1;
	КонецЕсли;
	
	Попытка
		ЗаписатьЖурналСканирования("ПолучитьНастройку.Старт", 
			СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("ПолучитьНастройку(%1, %2)", 
				ИмяУстройства, ИмяНастройки));
		ЗначениеНастройки = ПодключаемыйМодуль.ПолучитьНастройку(ИмяУстройства, ИмяНастройки);
		ЗаписатьЖурналСканирования("ПолучитьНастройку.Результат", 
			СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("ПолучитьНастройку(%1, %2) = %3", 
				ИмяУстройства, ИмяНастройки, ЗначениеНастройки));
		
		Возврат ЗначениеНастройки;
	Исключение
		ПредставлениеОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ЗаписатьЖурналСканирования("ПолучитьНастройку", ПредставлениеОшибки, Истина);
		ПоказатьОшибкуСканирования(ПодключаемыйМодуль, Форма, НСтр("ru='Не удалось получить настройки устройства.'"), ПредставлениеОшибки);
		Возврат -1;
	КонецПопытки;
	
КонецФункции

Функция ЕстьУстройства(Форма, ПодключаемыйМодуль, ПоказыватьОшибку = Истина) Экспорт
	ЗаписатьЖурналСканирования("ЕстьУстройства.Старт");
	Попытка
		ЕстьУстройства = ПодключаемыйМодуль.ЕстьУстройства();
		ЗаписатьЖурналСканирования("ЕстьУстройства.Результат", 
			СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("ЕстьУстройства() = %1", ЕстьУстройства));
	Исключение
		ПредставлениеОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ЗаписатьЖурналСканирования("ЕстьУстройства", ПредставлениеОшибки, Истина);
		Если ПоказыватьОшибку Тогда
			ПоказатьОшибкуСканирования(ПодключаемыйМодуль, Форма, НСтр("ru='Не удалось проверить наличие устройств'"), ПредставлениеОшибки);
		КонецЕсли;
		ЕстьУстройства = Ложь;
	КонецПопытки;
	
	Возврат ЕстьУстройства;
	
КонецФункции

Процедура НачатьСканирование(Форма, ПодключаемыйМодуль, ПараметрыСканирования) Экспорт
	
	ПараметрСжатие = ?(ВРег(ФорматКартинки) = "JPG", ПараметрыСканирования.КачествоJPG, ПараметрыСканирования.СжатиеTIFF);
	ТекстСобытия = "НачатьСканирование" + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("(%1, %2, %3, %4, %5, %6, %7, %8, %9)", 
		ПараметрыСканирования.ПоказыватьДиалог,
		ПараметрыСканирования.ВыбранноеУстройство,
		ПараметрыСканирования.ФорматКартинки,
		ПараметрыСканирования.Разрешение,
		ПараметрыСканирования.Цветность,
		ПараметрыСканирования.Поворот,
		ПараметрыСканирования.РазмерБумаги,
		ПараметрСжатие,
		ПараметрыСканирования.ДвустороннееСканирование);
	ЗаписатьЖурналСканирования("НачатьСканирование.Старт", ТекстСобытия);
		
	Попытка
		ПодключаемыйМодуль.НачатьСканирование(
			ПараметрыСканирования.ПоказыватьДиалог,
			ПараметрыСканирования.ВыбранноеУстройство,
			ПараметрыСканирования.ФорматКартинки,
			ПараметрыСканирования.Разрешение,
			ПараметрыСканирования.Цветность,
			ПараметрыСканирования.Поворот,
			ПараметрыСканирования.РазмерБумаги,
			ПараметрСжатие,
			ПараметрыСканирования.ДвустороннееСканирование);
		ЗаписатьЖурналСканирования("НачатьСканирование.Результат", ТекстСобытия);
	Исключение
		ПредставлениеОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ЗаписатьЖурналСканирования("НачатьСканирование", ПредставлениеОшибки, Истина);
		ПоказатьОшибкуСканирования(ПодключаемыйМодуль, Форма, НСтр("ru='Не удалось отсканировать документ'"), ПредставлениеОшибки);
	КонецПопытки;
	
КонецПроцедуры

Процедура ВключитьЛогированиеКомпоненты(ПодключаемыйМодуль, Знач Перезапуск = Ложь) Экспорт 
	ИдентификаторКлиента = ИдентификаторКлиента();
	ПараметрыЛогирования = РаботаСФайламиСлужебныйВызовСервера.ПараметрыЛогирования(ИдентификаторКлиента);
	
	Если Не Перезапуск Тогда
		Перезапуск = ПараметрыЛогирования.ДатаНачалаЛогированияСканирования = Дата(1,1,1);
	КонецЕсли;
	
	ИмяЛогФайла = ПараметрыЛогирования.ИмяЛогФайла;
	
	Если Перезапуск И ИмяЛогФайла <> Неопределено Тогда
		УстановитьИмяЛогФайла(ПодключаемыйМодуль, "");
		ФайлЛога = Новый Файл(ИмяЛогФайла);
		Если ФайлЛога.Существует() Тогда
			УдалитьФайлы(ИмяЛогФайла);
		КонецЕсли;
	КонецЕсли;	
	
	КаталогЖурналаСканирования = ПараметрыЛогирования.КаталогЖурналаСканирования;
	ИспользоватьКаталогЖурналаСканирования  = ПараметрыЛогирования.ИспользоватьКаталогЖурналаСканирования;
	
	Контекст = Новый Структура;
	Контекст.Вставить("ПодключаемыйМодуль", ПодключаемыйМодуль);
	
	ОповещениеПослеСозданияВременногоКаталогаДляПодключенияЛогФайлов = Новый ОписаниеОповещения("ОповещениеПослеСозданияВременногоКаталогаДляПодключенияЛогФайлов",
		ЭтотОбъект, Контекст);
	
	Если ИспользоватьКаталогЖурналаСканирования И КаталогЖурналаСканирования <> Неопределено Тогда
		ВыполнитьОбработкуОповещения(ОповещениеПослеСозданияВременногоКаталогаДляПодключенияЛогФайлов, КаталогЖурналаСканирования);
	ИначеЕсли Перезапуск И Не ЗначениеЗаполнено(ИмяЛогФайла) Тогда
		ФайловаяСистемаКлиент.СоздатьВременныйКаталог(ОповещениеПослеСозданияВременногоКаталогаДляПодключенияЛогФайлов);
	Иначе
		УстановитьИмяЛогФайла(ПодключаемыйМодуль, ИмяЛогФайла);
	КонецЕсли;
	
КонецПроцедуры

Процедура УстановитьИмяЛогФайла(ПодключаемыйМодуль, ИмяЛогФайла) 
	ЗаписатьЖурналСканирования("LogFilePath.УстановкаЗначения", 
		СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("LogFilePath = %1", ИмяЛогФайла));
	Попытка
		ПодключаемыйМодуль.LogFilePath = ИмяЛогФайла;
		ЗаписатьЖурналСканирования("LogFilePath.ЗначениеУстановлено");
	Исключение
		ПредставлениеОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ЗаписатьЖурналСканирования("LogFilePath", ПредставлениеОшибки, Истина);
	КонецПопытки;
КонецПроцедуры

Процедура ОповещениеПослеСозданияВременногоКаталогаДляПодключенияЛогФайлов(КаталогЖурналаСканирования, Контекст) Экспорт
		
	ИмяЛогФайла = КаталогЖурналаСканирования + ПолучитьРазделительПути() + "ImageScan.log";
	ПодключаемыйМодуль = Контекст.ПодключаемыйМодуль;
	УстановитьИмяЛогФайла(ПодключаемыйМодуль, ИмяЛогФайла);
	РаботаСФайламиСлужебныйВызовСервера.УстановитьПараметрыНачалаЛогирования(ИмяЛогФайла);
			
КонецПроцедуры

Процедура ЗаписатьЖурналСканирования(Событие, Комментарий = "", ЭтоОшибка = Ложь) Экспорт 
	
	ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(
		НСтр("ru='Сканирование изображений'", ОбщегоНазначенияКлиент.КодОсновногоЯзыка()) + "." + Событие,
		?(ЭтоОшибка, "Ошибка", "Информация"), Комментарий,, Истина);
	
КонецПроцедуры

Процедура ПоказатьОшибкуСканирования(ПодключаемыйМодуль, Форма, Заголовок, ПодробноеПредставлениеОшибки, 
	ТекстОшибки = "", РежимТребуетсяПомощь = Ложь) Экспорт

	ПараметрыОткрытияФормы = Новый Структура("Заголовок, ПодробноеПредставлениеОшибки", 
		Заголовок, ПодробноеПредставлениеОшибки);
	ПараметрыОткрытияФормы.Вставить("ТекстОшибки", ТекстОшибки);
	ПараметрыОткрытияФормы.Вставить("ИмяУстройстваСканирования", Форма.ИмяУстройстваСканирования);
	
	Контекст = Новый Структура("РежимТребуетсяПомощь", РежимТребуетсяПомощь);
	ПослеЗакрытияФормыОшибки = Новый ОписаниеОповещения("ПослеЗакрытияФормыОшибки", Форма, Контекст);
	ОткрытьФорму("Обработка.Сканирование.Форма.ОшибкаСканирования", ПараметрыОткрытияФормы, Форма,,,, ПослеЗакрытияФормыОшибки);
	
КонецПроцедуры

Функция БылаОшибкаСканирования() Экспорт
	
	ПараметрыЗаданияСканирования = ОбщегоНазначенияВызовСервера.ХранилищеОбщихНастроекЗагрузить("КомпонентаСканирования", "ПараметрыЗаданияСканирования", Неопределено);
	Возврат ПараметрыЗаданияСканирования <> Неопределено;
	
КонецФункции

Процедура УдалитьОшибкуСканирования(ПодключаемыйМодуль) Экспорт
	
	ОбщегоНазначенияВызовСервера.ХранилищеОбщихНастроекСохранить("КомпонентаСканирования", "ПараметрыЗаданияСканирования", Неопределено);
	ВключитьЛогированиеКомпоненты(ПодключаемыйМодуль, Истина);
	
КонецПроцедуры

Процедура ПолучитьТехническуюИнформацию(ПодробноеПредставлениеОшибки, ОповещениеПослеПолученияТехническойИнформации) Экспорт
	Режим = РежимДиалогаВыбораФайла.Сохранение;
	ДиалогОткрытияФайла = Новый ДиалогВыбораФайла(Режим);
	ДиалогОткрытияФайла.ПолноеИмяФайла = НСтр("ru='Техническая информация'");
	Фильтр = НСтр("ru = 'Отчет о проблеме'") + "(*.zip)|*.zip";
	ДиалогОткрытияФайла.Фильтр = Фильтр;
	ДиалогОткрытияФайла.МножественныйВыбор = Ложь;
	ДиалогОткрытияФайла.Заголовок = НСтр("ru='Сохранение технической информации о проблеме'");
	Если Не ДиалогОткрытияФайла.Выбрать() Тогда
		Возврат;
	КонецЕсли;
	МассивФайлов = ДиалогОткрытияФайла.ВыбранныеФайлы;
	Если МассивФайлов.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
		
	Контекст = Новый Структура();
	Контекст.Вставить("ПодробноеПредставлениеОшибки", ПодробноеПредставлениеОшибки);
	Контекст.Вставить("ОповещениеПослеПолученияТехническойИнформации", ОповещениеПослеПолученияТехническойИнформации);
	Контекст.Вставить("ИмяФайла", МассивФайлов[0]);
	ОповещениеПослеСозданияВременногоКаталогаДляЛогФайлов = Новый ОписаниеОповещения("ПослеСозданияВременногоКаталогаДляЛогФайлов", ЭтотОбъект, Контекст);
	ФайловаяСистемаКлиент.СоздатьВременныйКаталог(ОповещениеПослеСозданияВременногоКаталогаДляЛогФайлов);

КонецПроцедуры

Процедура ПослеСозданияВременногоКаталогаДляЛогФайлов(ИмяКаталога, Контекст) Экспорт
#Если Не ВебКлиент Тогда	
	ПодробноеПредставлениеОшибки = Контекст.ПодробноеПредставлениеОшибки;
	ОповещениеПослеПолученияТехническойИнформации = Контекст.ОповещениеПослеПолученияТехническойИнформации;
	ИмяФайла = Контекст.ИмяФайла;
	
	КаталогВременныхФайлов = ИмяКаталога + ПолучитьРазделительПути();
	ТехническаяИнформация = РаботаСФайламиСлужебныйВызовСервера.ТехническаяИнформация();
	
	ФайлыДляУдаления = Новый Массив;
	ЗаписьZIP = Новый ЗаписьZipФайла(ИмяФайла);
	ИмяЛогФайла = ТехническаяИнформация.ИмяЛогФайла;
	Если ИмяЛогФайла = Неопределено Тогда
		ЗаписатьЖурналСканирования("ФайлКомпоненты", НСтр("ru='Не задано имя файла журнала компоненты сканирования.'"), Истина);
	Иначе
		ЛогФайл = Новый Файл(ИмяЛогФайла);
		ИмяЛогФайлаДляСохранения = "";
		
		Если ЛогФайл.Существует() Тогда
			ИмяЛогФайлаДляСохранения = КаталогВременныхФайлов + "ImageScan.log";
			ПереместитьФайл(ИмяЛогФайла, ИмяЛогФайлаДляСохранения);
			ЗаписьZIP.Добавить(ИмяЛогФайлаДляСохранения);
		Иначе
			ЗаписатьЖурналСканирования("ФайлКомпоненты", СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru='Файл журнала компоненты сканирования не существует. %1'"), 
				ИмяЛогФайла), Истина);
		КонецЕсли;
	КонецЕсли;
	
	КонтекстИсходящий = Новый Структура;
	Контекст.Вставить("ЗаписьZIP", ЗаписьZIP);
	Контекст.Вставить("ФайлыДляУдаления", ФайлыДляУдаления);
	Контекст.Вставить("ПодробноеПредставлениеОшибки", ПодробноеПредставлениеОшибки);
	Контекст.Вставить("ОповещениеПослеПолученияТехническойИнформации", ОповещениеПослеПолученияТехническойИнформации);
	Контекст.Вставить("КаталогВременныхФайлов", КаталогВременныхФайлов);
	Контекст.Вставить("ТехническаяИнформация", ТехническаяИнформация);
	
	Текст =  НСтр("ru = 'Информация о компьютере:'") + Символы.ПС;
		
	СисИнфо = Новый СистемнаяИнформация;
	ПрограммаПросмотра = СисИнфо.ИнформацияПрограммыПросмотра;
	
	Если Не ПустаяСтрока(ПрограммаПросмотра) Тогда
		ПрограммаПросмотра = Символы.ПС + НСтр("ru = 'Программа просмотра:'") + " " + ПрограммаПросмотра;
	КонецЕсли;
	
	Текст = Текст + НСтр("ru = 'Операционная система:'") + " " + СисИнфо.ВерсияОС
		+ Символы.ПС + НСтр("ru = 'Версия приложения:'") + " " + СисИнфо.ВерсияПриложения
		+ Символы.ПС + НСтр("ru = 'Тип платформы:'") + " " + СисИнфо.ТипПлатформы
		+ ПрограммаПросмотра + Символы.ПС;
		
	Контекст.Вставить("ТекстСводнойИнформации", Текст);
		
	ОписаниеОповещения = Новый ОписаниеОповещения("СводнаяИнформацияПослеПолученияКомпоненты", ЭтотОбъект, Контекст);
	ПроинициализироватьКомпоненту(ОписаниеОповещения, Истина);
#КонецЕсли
КонецПроцедуры

Процедура СводнаяИнформацияПослеПолученияКомпоненты(РезультатИнициализации, Контекст) Экспорт
#Если Не ВебКлиент Тогда
	ТекстСводнойИнформации = Контекст.ТекстСводнойИнформации;
	ТехническаяИнформация = Контекст.ТехническаяИнформация;
	ФайлыДляУдаления = Контекст.ФайлыДляУдаления;
	ЗаписьZIP = Контекст.ЗаписьZIP;
	ИнформацияОКомпоненте = "";
	ПодключаемыйМодуль = Неопределено;
	Если РезультатИнициализации.Подключено Тогда
		Попытка
			ПодключаемыйМодуль = РезультатИнициализации.ПодключаемыйМодуль;
			ВерсияКомпоненты = ПодключаемыйМодуль.Версия();
			ИнформацияОКомпоненте = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Версия компоненты %1: %2'"), "ImageScan", ВерсияКомпоненты);
		Исключение
			ЗаписатьЖурналСканирования("Версия", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()), Истина);
		КонецПопытки;
	Иначе
		Возврат;
	КонецЕсли;
	
	ТекстСводнойИнформации = ТекстСводнойИнформации + Символы.ПС + ИнформацияОКомпоненте
		+ Символы.ПС + Символы.ПС + НСтр("ru='Техническая информация'") + ":" 
		+ Символы.ПС + Контекст.ПодробноеПредставлениеОшибки
		+ Символы.ПС + Символы.ПС;
		
	Если ОбщегоНазначенияКлиент.ИнформационнаяБазаФайловая() Тогда
		РежимРаботы = ?(ОбщегоНазначенияКлиент.КлиентПодключенЧерезВебСервер(),
			НСтр("ru = 'Файловый через веб'"), НСтр("ru = 'Файловый'"));
	Иначе
		РежимРаботы = НСтр("ru = 'Клиент-серверный'");
	КонецЕсли;
	
	ТекстСводнойИнформации = ТекстСводнойИнформации + НСтр("ru = 'Режим работы информационной базы'")+ " - " + РежимРаботы;
	
	ИмяФайлаСводнойИнформации = Контекст.КаталогВременныхФайлов + "СводнаяИнформация.txt";
	
	ТекстСводнойИнформации = ТекстСводнойИнформации + Символы.ПС 
		+ТехническаяИнформация.ТехническаяИнформацияОВерсияхПодсистемИРасширениях + Символы.ПС;
	СводнаяИнформация = ПолучитьДвоичныеДанныеИзСтроки(ТекстСводнойИнформации);
	СводнаяИнформация.Записать(ИмяФайлаСводнойИнформации);
	ФайлыДляУдаления.Добавить(ИмяФайлаСводнойИнформации);
	ЗаписьZIP.Добавить(ИмяФайлаСводнойИнформации);
	
	ИмяФайлаЖурнала = Контекст.КаталогВременныхФайлов + "ЖурналРегистрации.xml";
	ЖурналРегистрации = ТехническаяИнформация.ЖурналРегистрации; // ДвоичныеДанные
	ЖурналРегистрации.Записать(ИмяФайлаЖурнала); // АПК:287
	ФайлыДляУдаления.Добавить(ИмяФайлаЖурнала);
	ЗаписьZIP.Добавить(ИмяФайлаЖурнала); 
	
	КонтекстЗавершения = Новый Структура;
	КонтекстЗавершения.Вставить("ИмяФайлаСводнойИнформации", ИмяФайлаСводнойИнформации);
	КонтекстЗавершения.Вставить("ФайлыДляУдаления", Контекст.ФайлыДляУдаления);
	КонтекстЗавершения.Вставить("ОповещениеПослеПолученияТехническойИнформации", Контекст.ОповещениеПослеПолученияТехническойИнформации);
	ЗаписьZIP.Записать();
	Для Каждого ФайлДляУдаления Из ФайлыДляУдаления Цикл
		УдалитьФайлы(ФайлДляУдаления);
	КонецЦикла;
	УдалитьОшибкуСканирования(ПодключаемыйМодуль);
	
	Если Контекст.ОповещениеПослеПолученияТехническойИнформации <> Неопределено Тогда
		ВыполнитьОбработкуОповещения(Контекст.ОповещениеПослеПолученияТехническойИнформации);
	КонецЕсли; 
#КонецЕсли	
КонецПроцедуры

#Область УдалениеДанныхФайловИВерсий

Процедура УдалитьДанные(ОбработчикЗавершения, ФайлИлиВерсия, УникальныйИдентификатор) Экспорт
	
	Если Не ЗначениеЗаполнено(ФайлИлиВерсия) Тогда
		Возврат;
	КонецЕсли;
	
	Контекст = Новый Структура;
	Контекст.Вставить("ФайлИлиВерсия",           ФайлИлиВерсия);
	Контекст.Вставить("ОбработчикЗавершения",    ОбработчикЗавершения);
	Контекст.Вставить("УникальныйИдентификатор", УникальныйИдентификатор);
	
	Если ТипЗнч(ФайлИлиВерсия) <> Тип("СправочникСсылка.ВерсииФайлов") Тогда
		ТекстВопроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Удалить файл %1 без возможности восстановления?'"),
			Строка(ФайлИлиВерсия));
		ТекстЗаголовка = НСтр("ru = 'Удаление файла'");
	Иначе
		ТекстВопроса   = НСтр("ru = 'Удалить версию файла без возможности восстановления?'");
		ТекстЗаголовка = НСтр("ru = 'Удаление версии файла'");
	КонецЕсли;
	
	ПоказатьВопрос(Новый ОписаниеОповещения("УдалитьДанныеПослеОтветаНаВопрос", ЭтотОбъект, Контекст),
		ТекстВопроса, РежимДиалогаВопрос.ДаНет,, КодВозвратаДиалога.Нет, ТекстЗаголовка, КодВозвратаДиалога.Нет);
	
КонецПроцедуры

Процедура УдалитьДанныеПослеОтветаНаВопрос(Ответ, Контекст) Экспорт
	
	Если Ответ <> КодВозвратаДиалога.Да Тогда
		Возврат;
	КонецЕсли;
	
	Результат = РаботаСФайламиСлужебныйВызовСервера.РезультатУдаленияФайлов(
		ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Контекст.ФайлИлиВерсия),
		Контекст.УникальныйИдентификатор);
	Результат = Результат[Контекст.ФайлИлиВерсия];
	
	Если Результат.Файлы.Количество() > 0 Тогда
		Результат.Вставить("ИндексУдаляемогоФайла", 0);
		Результат.Вставить("ОбработчикЗавершения", Контекст.ОбработчикЗавершения);
		НачатьУдалениеФайлаИзКеша(Результат);
	Иначе
		ОповеститьОбУдаленииДанных(Контекст.ОбработчикЗавершения, Результат.ТекстПредупреждения);
	КонецЕсли;
	
КонецПроцедуры

Процедура НачатьУдалениеФайлаИзКеша(Контекст)
	
	Оповещение = Новый ОписаниеОповещения("ПослеУдаленияФайлаИзКеша", ЭтотОбъект, Контекст);
	УдалитьФайлИзРабочегоКаталога(Оповещение, Контекст.Файлы[Контекст.ИндексУдаляемогоФайла], Истина);
	
КонецПроцедуры

Процедура ПослеУдаленияФайлаИзКеша(РезультатУдаления, Контекст) Экспорт
	
	Если Контекст.ИндексУдаляемогоФайла < Контекст.Файлы.Количество() - 1 Тогда
		Контекст.ИндексУдаляемогоФайла = Контекст.ИндексУдаляемогоФайла + 1;
		НачатьУдалениеФайлаИзКеша(Контекст);
		Возврат;
	КонецЕсли;
	
	ОповеститьОбУдаленииДанных(Контекст.ОбработчикЗавершения, Контекст.ТекстПредупреждения)
	
КонецПроцедуры

Процедура ОповеститьОбУдаленииДанных(ОбработчикЗавершения, ТекстПредупреждения)
	
	Оповестить("Запись_Файл", ПараметрыОповещенияЗаписиФайла());
	Если Не ПустаяСтрока(ТекстПредупреждения) Тогда
		ПоказатьПредупреждение(ОбработчикЗавершения, ТекстПредупреждения);
	ИначеЕсли ОбработчикЗавершения <> Неопределено Тогда
		ВыполнитьОбработкуОповещения(ОбработчикЗавершения);
	КонецЕсли;
	
КонецПроцедуры

Процедура ИзменитьОтборПоПометкеУдаления(Область, КнопкаКоманды) Экспорт
	
	КнопкаКоманды.Пометка = Не КнопкаКоманды.Пометка;
	ОбщегоНазначенияКлиентСервер.ИзменитьЭлементыОтбора(Область, "ПометкаУдаления",
		"СкрыватьПометкуУдаленияПоУмолчанию", Ложь, ВидСравненияКомпоновкиДанных.Равно,
		Не КнопкаКоманды.Пометка, РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный);
		
КонецПроцедуры

Процедура УдалитьДанныеФайлов(ОбработчикЗавершения, ФайлыИлиВерсии, УникальныйИдентификатор) Экспорт
	
	Если ФайлыИлиВерсии.Количество() = 0 Тогда
		ВыполнитьОбработкуОповещения(ОбработчикЗавершения, Неопределено);
	КонецЕсли;
	
	Контекст = Новый Структура;
	Контекст.Вставить("ФайлыИлиВерсии",           ФайлыИлиВерсии);
	Контекст.Вставить("ОбработчикЗавершения",    ОбработчикЗавершения);
	Контекст.Вставить("УникальныйИдентификатор", УникальныйИдентификатор);
	
	ФайлИлиВерсия = ФайлыИлиВерсии[0];
	Если ФайлыИлиВерсии.Количество() = 1 Тогда
		ТекстВопроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Удалить файл %1 без возможности восстановления?'"),
			Строка(ФайлИлиВерсия));
		ТекстЗаголовка = НСтр("ru = 'Удаление файла'");
	Иначе
		ТекстВопроса = НСтр("ru = 'Удалить файлы без возможности восстановления?'");
		ТекстЗаголовка = НСтр("ru = 'Удаление файлов'");
	КонецЕсли;
	
	ПоказатьВопрос(Новый ОписаниеОповещения("УдалитьДанныеФайловПослеОтветаНаВопрос", ЭтотОбъект, Контекст),
		ТекстВопроса, РежимДиалогаВопрос.ДаНет,, КодВозвратаДиалога.Нет, ТекстЗаголовка, КодВозвратаДиалога.Нет);
КонецПроцедуры

Процедура УдалитьДанныеФайловПослеОтветаНаВопрос(Ответ, Контекст) Экспорт
	
	Если Ответ <> КодВозвратаДиалога.Да Тогда
		Возврат;
	КонецЕсли;
	
	РезультатыУдаления = РаботаСФайламиСлужебныйВызовСервера.РезультатУдаленияФайлов(
		Контекст.ФайлыИлиВерсии, Контекст.УникальныйИдентификатор);
		
	Предупреждения = Новый Соответствие;
	Результат = Новый Структура("Файлы,ИндексУдаляемогоФайла,ОбработчикЗавершения,ТекстПредупреждения", Новый Массив, 0);
	
	Для Каждого РезультатУдаления Из РезультатыУдаления Цикл
		Если РезультатУдаления.Значение.Файлы.Количество() > 0 Тогда
			ОбщегоНазначенияКлиентСервер.ДополнитьМассив(Результат.Файлы, РезультатУдаления.Значение.Файлы);
		Иначе
			Предупреждения.Вставить(РезультатУдаления.Ключ, РезультатУдаления.Значение.ТекстПредупреждения);
		КонецЕсли;
	КонецЦикла;
	
	Если Результат.Файлы.Количество() > 0 Тогда
		
		Результат.Вставить("ИндексУдаляемогоФайла", 0);
		Результат.Вставить("ОбработчикЗавершения", Контекст.ОбработчикЗавершения);
		
		НачатьУдалениеФайлаИзКеша(Результат);
		
	КонецЕсли;
	
	Если Предупреждения.Количество() > 0 Тогда
		ТекстПредупреждения = "";
		Для Каждого Предупреждение Из Предупреждения Цикл
			ТекстПредупреждения = ?(ТекстПредупреждения = "", "", Символы.ПС)
				+ СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru='%1: %2'"), Предупреждение.Ключ, Предупреждение.Значение);
		КонецЦикла;
		ОповеститьОбУдаленииДанных(Контекст.ОбработчикЗавершения, ТекстПредупреждения);
	КонецЕсли;
	
КонецПроцедуры
	
#КонецОбласти

#КонецОбласти
